Browse Source

initial code import

mom040267 11 years ago
commit
702b29bc22
100 changed files with 16408 additions and 0 deletions
  1. 46 0
      AUTHORS
  2. 970 0
      ChangeLog
  3. 963 0
      INSTALL
  4. 31 0
      LICENSE
  5. 127 0
      LICENSE.OpenSSL
  6. 173 0
      Makefile.in
  7. 2 0
      NOTE
  8. 239 0
      README.turnadmin
  9. 880 0
      README.turnserver
  10. 329 0
      README.turnutils
  11. 101 0
      STATUS
  12. 128 0
      TODO
  13. 1063 0
      configure
  14. 23 0
      examples/etc/turn_client_cert.pem
  15. 27 0
      examples/etc/turn_client_pkey.pem
  16. 22 0
      examples/etc/turn_server_cert.pem
  17. 27 0
      examples/etc/turn_server_pkey.pem
  18. 589 0
      examples/etc/turnserver.conf
  19. 23 0
      examples/etc/turnuserdb.conf
  20. 35 0
      examples/scripts/basic/dos_attack.sh
  21. 30 0
      examples/scripts/basic/relay.sh
  22. 27 0
      examples/scripts/basic/tcp_client.sh
  23. 25 0
      examples/scripts/basic/tcp_client_c2c_tcp_relay.sh
  24. 29 0
      examples/scripts/basic/udp_c2c_client.sh
  25. 28 0
      examples/scripts/basic/udp_client.sh
  26. 38 0
      examples/scripts/loadbalance/master_relay.sh
  27. 37 0
      examples/scripts/loadbalance/slave_relay_1.sh
  28. 37 0
      examples/scripts/loadbalance/slave_relay_2.sh
  29. 29 0
      examples/scripts/loadbalance/tcp_c2c_tcp_relay.sh
  30. 31 0
      examples/scripts/loadbalance/udp_c2c.sh
  31. 49 0
      examples/scripts/longtermsecure/secure_dos_attack.sh
  32. 36 0
      examples/scripts/longtermsecure/secure_dtls_client.sh
  33. 36 0
      examples/scripts/longtermsecure/secure_dtls_client_cert.sh
  34. 35 0
      examples/scripts/longtermsecure/secure_relay.sh
  35. 38 0
      examples/scripts/longtermsecure/secure_relay_cert.sh
  36. 31 0
      examples/scripts/longtermsecure/secure_tcp_client.sh
  37. 31 0
      examples/scripts/longtermsecure/secure_tcp_client_c2c_tcp_relay.sh
  38. 34 0
      examples/scripts/longtermsecure/secure_tls_client.sh
  39. 35 0
      examples/scripts/longtermsecure/secure_tls_client_c2c_tcp_relay.sh
  40. 36 0
      examples/scripts/longtermsecure/secure_tls_client_cert.sh
  41. 32 0
      examples/scripts/longtermsecure/secure_udp_c2c.sh
  42. 32 0
      examples/scripts/longtermsecure/secure_udp_client.sh
  43. 34 0
      examples/scripts/longtermsecuredb/secure_relay_with_db_mysql.sh
  44. 37 0
      examples/scripts/longtermsecuredb/secure_relay_with_db_psql.sh
  45. 37 0
      examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh
  46. 36 0
      examples/scripts/mobile/mobile_dtls_client.sh
  47. 36 0
      examples/scripts/mobile/mobile_relay.sh
  48. 32 0
      examples/scripts/mobile/mobile_tcp_client.sh
  49. 36 0
      examples/scripts/mobile/mobile_tls_client_c2c_tcp_relay.sh
  50. 33 0
      examples/scripts/mobile/mobile_udp_client.sh
  51. 16 0
      examples/scripts/peer.sh
  52. 26 0
      examples/scripts/readme.txt
  53. 36 0
      examples/scripts/restapi/secure_relay_secret.sh
  54. 38 0
      examples/scripts/restapi/secure_relay_secret_with_db_mysql.sh
  55. 38 0
      examples/scripts/restapi/secure_relay_secret_with_db_psql.sh
  56. 38 0
      examples/scripts/restapi/secure_relay_secret_with_db_redis.sh
  57. 31 0
      examples/scripts/restapi/secure_udp_client_with_secret.sh
  58. 105 0
      examples/scripts/restapi/shared_secret_maintainer.pl
  59. 14 0
      examples/scripts/rfc5769.sh
  60. 130 0
      examples/scripts/selfloadbalance/secure_dos_attack.sh
  61. 42 0
      examples/scripts/selfloadbalance/secure_relay.sh
  62. 37 0
      examples/scripts/shorttermsecure/secure_relay_short_term_mech.sh
  63. 31 0
      examples/scripts/shorttermsecure/secure_tcp_client_c2c_tcp_relay_short_term.sh
  64. 30 0
      examples/scripts/shorttermsecure/secure_udp_client_short_term.sh
  65. 15 0
      make-man.sh
  66. 1 0
      man/man1/coturn.1
  67. 325 0
      man/man1/turnadmin.1
  68. 1121 0
      man/man1/turnserver.1
  69. 439 0
      man/man1/turnutils.1
  70. 1 0
      man/man1/turnutils_peer.1
  71. 1 0
      man/man1/turnutils_stunclient.1
  72. 1 0
      man/man1/turnutils_uclient.1
  73. 35 0
      postinstall.txt
  74. 98 0
      rpm/CentOS6.pre.build.sh
  75. 20 0
      rpm/Fedora.pre.build.sh
  76. 43 0
      rpm/build.instructions.txt
  77. 14 0
      rpm/build.settings.sh
  78. 98 0
      rpm/build.sh
  79. 26 0
      rpm/common.pre.build.sh
  80. 39 0
      rpm/epel.install.sh
  81. 82 0
      rpm/turnserver.init.el
  82. 15 0
      rpm/turnserver.service.fc
  83. 358 0
      rpm/turnserver.spec
  84. 5 0
      rpm/turnserver.sysconfig
  85. 19 0
      rpm/uninstall.turnserver.sh
  86. 902 0
      src/apps/common/apputils.c
  87. 163 0
      src/apps/common/apputils.h
  88. 383 0
      src/apps/common/hiredis_libevent2.c
  89. 67 0
      src/apps/common/hiredis_libevent2.h
  90. 643 0
      src/apps/common/ns_turn_utils.c
  91. 86 0
      src/apps/common/ns_turn_utils.h
  92. 252 0
      src/apps/common/stun_buffer.c
  93. 131 0
      src/apps/common/stun_buffer.h
  94. 102 0
      src/apps/peer/mainudpserver.c
  95. 172 0
      src/apps/peer/udpserver.c
  96. 76 0
      src/apps/peer/udpserver.h
  97. 954 0
      src/apps/relay/dtls_listener.c
  98. 72 0
      src/apps/relay/dtls_listener.h
  99. 1545 0
      src/apps/relay/libtelnet.c
  100. 677 0
      src/apps/relay/libtelnet.h

+ 46 - 0
AUTHORS

@@ -0,0 +1,46 @@
+Oleg Moskalenko <[email protected]> :
+	General design and implementation
+	(2011-2013);
+	
+Gabor Kovesdan, http://kovesdan.org :
+	FreeBSD packaging
+	(since v1.5.2.6);
+	
+Daniel Pocock, http://danielpocock.com :
+	Debian packaging
+	(since v1.8.3.6);
+	
+John Selbie ([email protected]) :
+	Stuntman interoperability, RFC5780 fixes 
+	MS Windows port work
+	(since v1.8.3.6);
+	
+Lee Sylvester <[email protected]> :
+	Status and statistics - ideas and pilot implementation
+	(since v1.8.4.0);
+
+Erik Johnston <[email protected]> :
+	Access Control Lists, 2013 
+	(since v1.8.5.0);
+
+Roman Lisagor <[email protected]> :
+	Testing, code optimization
+	(since v1.8.6.0);
+
+Vladimir Tsanev <[email protected]> :
+	configure script and Makefile fixes,
+	Arch Linux port
+	(since v1.8.6.1);
+	 
+Po-sheng Lin <[email protected]> :
+	Libevent dependencies cleaning
+	(since v2.0.1.1);
+
+Peter Dunkley <[email protected]> :
+	CentOS/Fedora port
+	(since v2.6.6.1)
+
+Mutsutoshi Yoshimoto <[email protected]>
+	TCP routing: testing and bug fixes
+	(since v3.2.2.7)
+

+ 970 - 0
ChangeLog

@@ -0,0 +1,970 @@
+04/20/2014 Oleg Moskalenko <[email protected]>
+Version 3.3.0.0 'Threetrees':
+	- multi-tenant server.
+
+04/13/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.3.6 'Marshal West':
+	- Addresses logging fixed.
+	- Redis admin options fixed.
+	- Redis compilation cleaned.
+
+04/07/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.3.5 'Marshal West':
+	- Mobile allocation quota fixed (issue 121);
+	- --simple-log option added (Issue 122);
+	- documentation fixes (REST API, Redis).
+
+04/06/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.3.4 'Marshal West':
+	- Mobile TCP sessions fixed (issue 120);
+	- log information improvements.
+
+04/04/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.3.3 'Marshal West':
+	- Pkey and cert file descriptors to be closed
+	on initialization (issue 118);
+	- Address bind indefinite cycle on start-up fixed
+	(Issue 119);
+	- Allocation counters time lag improved.
+
+03/30/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.3.2 'Marshal West':
+	- Allocation counters fixed (issue 117);
+	- a possible core dump in the server code fixed;
+	- a possible memory leak in server fixed.
+
+03/29/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.3.1 'Marshal West':
+	- TCP congestion avoidance completed.
+	- Read and write streams are treated separately in
+	bandwidth control.
+	- Test client fixed.
+	- Experimental SHA256 key storage supported.
+
+03/17/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.912 'Marshal West':
+	- TCP-in-TCP congestion avoidance implemented.
+	- UDP-in-TCP congestion avoidance improved.
+	- Alternate-server code cleaned.
+
+03/10/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.911 'Marshal West':
+	- "Congestion control" for UDP-inside-TCP tunneling;
+	- memory management improvements;
+	- socket logging improvements;
+	- debug info added to CentOS and Fedora RPMs;
+	- TCP traffic buffering improved;
+	- Thread barriers cleaned;
+	- TCP memory leak fixed;
+	- minor TCP test client improvement.
+
+03/09/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.910 'Marshal West':
+	- Log messages extended and cleaned.
+	- Some memory cleaning.
+
+03/02/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.9 'Marshal West':
+	- Issue 113 fixed (TCP rate limit fixed);
+	- Issue 114 fixed (TCP stability).
+
+02/18/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.8 'Marshal West':
+	- Issue 102: SO_BSDCOMPAT socket option removed;
+	- Issue 104: check for the REALM attribute value;
+	- Issue 105: no-cli segfault fixed;
+	- Issue 106: MESSAGE-INTEGRITY removed from DATA indication;
+	- Issue 108: Server should return 438 on unknown nonce;
+	- Issue 109: make the random functions stronger (mostly for
+	transaction ID and for nonce);
+	- Issue 111: fix valgrind warning on memory initialization.
+	- Issue 112: RTCP sockets logging.
+
+02/12/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.7 'Marshal West':
+	- Possible indefinite cycle fixed in TCP/TCP routing (Issue 99);
+	- Address 0.0.0.0 can be used as a listener address (Issue 100);
+	- DHCP-configured servers supported (Issue 101);
+
+02/04/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.6 'Marshal West':
+	- Channel traffic memory copy elimination.
+	- Send indication memory copy elimination.
+	- DTLS traffic processing memory copy eliminated.
+	- Mobility forbidden error code number fixed - according to the new draft document.
+	- getsockname() usage minimized.
+	- port allocation improved.
+	- default relay behavior fixed (when no relay addresses defined).
+	- atomic create permission request handling (Issue 97).
+
+01/25/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.5 'Marshal West':
+	- code optimization.
+
+01/24/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.4 'Marshal West':
+	- HMAC key handling fixed (Issue 96).
+
+01/23/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.3 'Marshal West':
+	- Security fix (issue 95).
+	- Default "implicit" relay IP allocation policy is more usable
+		(issue 94 fixed).
+	- SSLv2 fixed (for those who are still using it)
+		(issue 93 fixed).
+	- Cosmetic changes.
+
+01/19/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.2.1 'Marshal West':
+	- CPU/memory cache optimization (memory locality).
+	- torture tests enhanced.
+	- stability fixes.
+	- minor possible memory leak fix.
+	- new TLS options: --no-sslv2, --no-sslv3, --no-tlsv1,
+		--no-tlsv1_1, --no-tlsv1_2
+
+01/06/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.1.4 'Marshal West':
+	- Linux epoll performance improvements.
+	- DTLS minor fix.
+
+01/06/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.1.3 'Marshal West':
+	- Telnet client added to installation when necessary.
+
+01/05/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.1.2 'Marshal West':
+	- Config file adjusted for DragonFly.
+
+01/03/2014 Oleg Moskalenko <[email protected]>
+Version 3.2.1.1 'Marshal West':
+	- Minor TLS fix.
+	- Default cipher list is DEFAULT now.
+
+12/26/2013 Oleg Moskalenko <[email protected]>
+Version 3.2.1.0 'Marshal West':
+	- Optimized TCP network engine for Linux 3.9+.
+	- Security fix: DH and ECDH temporary keys are now
+		regenerated for each TLS or DTLS session.
+	- Fix for systems with multiple CPU cores (more than 128).
+	- DH TLS key now can be configured as 566, 1066 (default) or 2066 bits.
+	- DH TLS key can be taken from a PEM file.
+	- Issue 91 (test client crash) fixed.
+	- Configurable net engine type.
+
+12/25/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.6.0 'Arch Lector':
+	- Timers optimization: linked list timers structure
+		for often-used intervals.
+
+12/23/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.5.3 'Arch Lector':
+	- HTTP "keep-alive" support improved.
+	- TCP channel "fortification".
+
+12/19/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.5.1 'Arch Lector':
+	- Private key password allowed for encrypted keys.
+	- HTTP "keep-alive" supported.
+	- "psd" CLI command added (ps dump to file).
+
+12/18/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.4.2 'Arch Lector':
+	- Time functions optimization.
+	- Online changes to the alternate servers list thru telnet CLI.
+	- Certificate chain files allowed.
+
+12/13/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.3.1 'Arch Lector':
+	- "Start time" ps command info added.
+	- Protocol option added to "pu" command.
+	- "Delete allocation" debug message fixed.
+	- "Allocation id" debug info message fixed.
+	- RFC6062 usage statistics fixed.
+	- Info/Debug messages cleaned.
+
+12/11/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.2.3 'Arch Lector':
+	- CentOS 6 package fixed.
+
+12/10/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.2.2 'Arch Lector':
+	- ps output typo fixed (TLS params).
+	- configurable EC curve name.
+	- CLI TLS-related information extended.
+	- "print users" (pu) CLI command added.
+
+12/09/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.2.1 'Arch Lector':
+	- DH cipher suites basic implementation.
+	- Elliptic Curve cipher suites basic implementation.
+	- RFC 6062 crash fixed.
+	- More CLI parameters added.
+	- Redis allocation statistics fixed.
+	- Number of cli max session lines configurable.
+	- uclient cipher suite configurable.
+
+12/08/2013 Oleg Moskalenko <[email protected]>
+Version 3.1.1.0 'Arch Lector':
+	- Telnet CLI.
+	- RFC 6062 internal messaging fixed.
+	- Server relay endpoints (a non-standard feature).
+	- "atomic line" stdout log print.
+	- printed help minor fix.
+	- client program does not necessary
+		require certificate for TLS.
+	- docs fixes.
+	- allocation quota bug fixed.
+
+11/29/2013 Oleg Moskalenko <[email protected]>
+Version 3.0.2.1 'Practical Frost':
+	- TCP stability fixes.
+	- RFC 6062 "first packet(s)" bug fixed.
+	- RFC 6062 stability fixes.
+	- Multithreaded Mobile ICE.
+
+11/28/2013 Oleg Moskalenko <[email protected]>
+Version 3.0.1.4 'Practical Frost':
+	- CentOS/Fedora packaging fixed.
+	- PID file fixed.
+
+11/26/2013 Oleg Moskalenko <[email protected]>
+Version 3.0.1.3 'Practical Frost':
+	- Misc cosmetic changes.
+	- CentOS/Fedora packaging fixed.
+
+11/25/2013 Oleg Moskalenko <[email protected]>
+Version 3.0.1.2 'Practical Frost':
+	- Mobility draft implemented.
+	- DTLS communications fixes.
+	- UDP Linux optimization.
+	- Log output time starts with 0.
+	- A new "drop root privileges" options:
+		--proc-user and --proc-group added.
+	- SHA256 agility updated: 426 error code on too weak SHA function.
+	- "-m 0" and "-m 1" options improved.
+	- non-threading environment support dropped.
+	- stability fixes.
+	- OpenSUSE support added.
+
+11/10/2013 Oleg Moskalenko <[email protected]>
+Version 3.0.0.0 'Practical Frost':
+	- New network engine for Linux kernel 3.9+.
+
+11/08/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.7.2 'Harding Grim':
+	- SHA256 agility updated: 441 error code on too weak SHA function.
+
+11/07/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.7.1 'Harding Grim':
+	- CentOS  / Fedora uninstall script.
+	- Debian compilation error fixed.
+	- OpenSSL 0.9.7 and earlier build fixed.
+	- NetBSD build fixed.
+
+11/03/2013 Oleg Moskalenko <[email protected]>,
+	Peter Dunkley <[email protected]>
+Version 2.6.7.0 'Harding Grim':
+	- CentOS 6 pre-compiled distribution.
+	- Fedora pre-compiled distribution.
+	- TURN_NO_TLS case compilation cleaning.
+	- Text files cleaning.
+	- Issue 68 fixed (no-stun option added).
+
+10/27/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.6.1 'Harding Grim':
+	- SHA256 added as a non-standard message integrity option.
+	- CentOS rpm specs added.
+	- Peter Dunkley added to the authors list.
+
+10/20/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.6.0 'Harding Grim':
+	- Cygwin loopback relay interfaces fixed (Issue 62).
+	- rpath added to the Makefile (Issue 63).
+	- CONFLICTS added to FreeBSD port Makefile (Issue 64).
+	- Certificate check options, for server and for the test client (Issue 65).
+	- Some compilation cleaning.
+
+10/09/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.5.2 'Harding Grim':
+	- Documentation changes.
+	- Redis-related memory leak fixed (Issue 61).
+
+09/25/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.4.1 'Harding Grim':
+	- Crash on uninitialized redis db name is fixed (Issue 59).
+	- Optional authentication of STUN Binding request is implemented (Issue 60).
+
+09/16/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.3.1 'Harding Grim':
+	- Issue 58: support changing white/black IP lists while server is running.
+	database tables (keys for redis) added for that new functionality.
+
+09/03/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.2.2 'Harding Grim':
+	- Issue 52: RFC 6062 relay endpoints connection process
+	fixed for Linux pre-3.9 kernel.
+
+09/03/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.2.1 'Harding Grim':
+	- UDP performance improvements.
+	- Issue 56: DTLS scaleability improvements.
+	- Issue 55: DTLS support in Cygwin.
+	- Issue 57: --pidfile option
+	- Issue 52: RFC 6062 relay endpoints connection process fixed.
+	- Issue 53: Fingerprints added to the indications.
+	- Issue 54: Long-term credentials mechanism integrity and software attributes
+	added to the indications.
+
+08/11/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.1.4 'Harding Grim':
+	- UDP memory leak fixed.
+
+08/11/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.1.3 'Harding Grim':
+	- DTLS crash fix.
+
+08/10/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.1.2 'Harding Grim':
+	- TLS buffer decreased to avoid memory problems.
+	- TLS BIO object fix.
+	- UDP socket open/reopen process fixed.
+
+08/08/2013 Oleg Moskalenko <[email protected]>
+Version 2.6.1.1 'Harding Grim':
+	- Network optimization:
+		* "pure" UDP setup optimized (when no DTLS configured);
+		* Auxiliary listening endpoints (configured by
+			--aux-server=<ip:port>).
+		* --udp-self-balance option to balance the UDP traffic
+			among the aux endpoints (for clients supporting
+			300 ALTERNATE-SERVER response).
+	- Security improvements:
+        * no authentication required on the load balancer server (Issue 50).
+		* REST API improvement:
+			= --secret-ts-exp-time option deprecated;
+			= In REST API timestamp, we are now using
+				the expiration time (Issue 31).
+		* Configurable cipher suite in the TURN server.
+		* SSL3 support.
+		* TLS 1.1 and 1.2 support.
+		* SSL2 "encapsulation" mode support.
+		* NULL OpenSSL cipher is allowed to be negotiated between
+			server and client.
+		* -U option (NULL cipher) added to the test client.
+		* DTLS crash fixed on overload.
+	- STUN enhancements and fixes:
+		* Classic STUN transaction ID fixed (Issue 48).
+		* Classic STUN attribute ERROR fixed (Issue 49).
+		* Unused RFC 5780 functionality removed from TCP, TLS and DTLS relays.
+		* resources optimization for stun-only: short connection expiration time.
+		
+07/26/2013 Oleg Moskalenko <[email protected]>,
+			Vladimir Tsanev <[email protected]>
+Version 2.5.2.1 'Shivers':
+	- log file placement changes.
+	- Base64 encode/decode memory initialization fix.
+
+07/23/2013 Oleg Moskalenko <[email protected]>,
+			Po-sheng Lin <[email protected]>
+Version 2.5.1.2 'Shivers':
+	- getopt fix in client test programs.
+	- cosmetic changes.
+	- allow anonymous alternate-server functionality.
+
+07/21/2013 Oleg Moskalenko <[email protected]>
+Version 2.5.1.1 'Shivers':
+	- Improved "split" network engine:
+	two different threading models for TCP and UDP.
+	- DTLS crash fixed.
+	- Multithreading with Cygwin.
+
+07/20/2013 Oleg Moskalenko <[email protected]>
+Version 2.1.3.1 'Shivers':
+	- DTLS improvements for DOS attacks
+	- deeper optimization for DOS attack (mostly for Linux)
+
+07/19/2013 Oleg Moskalenko <[email protected]>
+Version 2.1.2.0 'Shivers':
+	- deeper optimization for DOS attack (mostly for Linux)
+
+07/18/2013 Oleg Moskalenko <[email protected]>,
+			Po-sheng Lin <[email protected]>
+Version 2.1.1.1 'Shivers':
+	- udp fixes.
+	- Makefile cleaning.
+	- Dependencies cleaning.
+	- DOS attack client emulation.
+	- DOS attack defense logic added to the server.
+
+07/14/2013 Oleg Moskalenko <[email protected]>
+Version 2.0.0.0 'Shivers':
+	- new networking engine:
+		- scalable UDP socket model.
+		- multithreaded TCP relay implemented.
+		- race condition fixed in authentication of TCP sessions.
+		- Cygwin "port" fixed.
+
+06/23/2013 Oleg Moskalenko <[email protected]>,
+			Vladimir Tsanev <[email protected]>
+Version 1.8.7.0 'Black Dow':
+
+	- Added support for obsolete "classic" STUN RFC 3489;
+	- Full TURN support for Cygwin implemented: MS-Win UDP sockets fixed;
+	- Relay threads number changed;
+	- Fedora warnings fixed;
+	- turndb/testdbsetup.sh example file added;
+	- Multiple Makefile and ./configure script fixes implemented:
+		* Changes taken from Arch Linux port;
+		* Manpages installation and deinstallation;
+		* rfc5769check utility removed from installation, it is used for the
+		compilation result test only and makes no sense for the end user;
+		* "--parameter" format support in ./configure script; it allows
+		simpler native OS package definitions (like in Debian package);
+		* Mac OS X linking warnings removed.
+		* pthread test fixed.
+
+06/08/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.6.3 'Black Dow':
+
+	- DONT-FRAGMENT flag removed on UDP listening (clients-facing) sockets.
+	- UDP fix for Cygwin only: UDP channels work fine now.
+	- docs fixes.
+
+06/06/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.6.2 'Black Dow':
+
+	- Just cosmetic re-packaging for Debian, tarball warnings removed.
+
+06/05/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.6.1 'Black Dow':
+
+	- Peer permissions bug fixed.
+
+06/03/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.6.0 'Black Dow':
+
+	- Optimization.
+	- Mac OS X compilation fixes.
+
+06/01/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.5.4 'Black Dow':
+
+	- Issues 29 and 30 fixed (channels padding).
+	- minor fixes.
+	- Mac OS X compilation fixes.
+	- Cygwin-related compilation fixes and INSTALL additions.
+
+05/31/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.5.3 'Black Dow':
+
+	- REST API extra script example and docs extention.
+
+05/26/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.5.1 'Black Dow':
+
+	- Config file parsing fixed (Issue 28)
+
+05/20/2013 Oleg Moskalenko <[email protected]>,
+			Erik Johnston <[email protected]>
+Version 1.8.5.0 'Black Dow':
+
+	- IP access control lists.
+	- log file name fix.
+	- alt-* ports default behavior changed.
+	- "passive TCP" option in uclient.
+
+05/18/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.4.5 'Black Dow':
+
+	- socket conditions cleaned (SIGPIPE, etc)
+
+05/17/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.4.4 'Black Dow':
+
+	- configuration and installation adjusted for:
+		- NetBSD;
+		- Solaris;
+		- OpenBSD;
+	- Screen messages fixed;
+	- code security fixes.
+
+05/15/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.4.3 'Black Dow':
+
+	- Compilation warning removed.
+	- Log file fixed (Issue 26)
+
+05/15/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.4.2 'Black Dow':
+
+	- repackaging for Debian compliance. Docs separated.
+
+05/14/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.4.1 'Black Dow':
+
+        - Cosmetics (docs, warnings, etc).
+        - More complex case of TURN-server-behind-NAT is implemented,
+        when multiple public-ip/private-ip mappings are involved.
+
+05/13/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.4.0 'Black Dow':
+
+        - Redis DB support added.
+        - Crash on help text fixed.
+        - Max allocation time can be changed in the command-line or
+        in the config file.
+
+05/09/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.9 'Black Dow':
+
+        - No changes - just the tarball is repackaged for Debian compatibility.
+
+05/07/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.8 'Black Dow':
+
+	- multicast and loopback addresses disallow options added.
+	- option to direct all log messages to the system log (syslog).
+
+05/02/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.7 'Black Dow':
+
+	- Allocation status log.
+
+05/01/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.6 'Black Dow':
+
+	- Stuntman client interoperability fixed.
+	- Manpages installation fixed.
+
+04/30/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.5 'Black Dow':
+
+	- Lintian fixes.
+
+04/27/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.4 'Black Dow':
+
+	- Installation fixes.
+
+04/26/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.3 'Black Dow':
+
+	- Log file midnight rollover implemented (Issue 15).
+
+04/25/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.1 'Black Dow':
+
+	- Configurable REST API separator symbol (Issue 16).
+	- Stale Nonce bug fixed (Issue 17).
+	- Minor client fix.
+
+04/21/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.3.0 'Black Dow':
+
+	- STUN stand-alone functionality improved according to RFC 5389.
+	- ALTERNATE-SERVER implemented as "light" load balancing feature.
+	- stun-only option implemented.
+	- scripts directory reorganized.
+
+04/19/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.2.1 'Black Dow':
+
+	- Misc docs fixes.
+
+04/13/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.2.0 'Black Dow':
+
+	- Multiple database shared secrets supported for REST API.
+	- Added support for some OpenSSL FIPS versions (like openssl 0.9.8e-fips-rhel5).
+
+04/13/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.1.3 'Black Dow':
+
+	- Maintenance (docs, etc).
+	- Added partial support for Cygwin. Only TCP & TLS protocols
+	are support for client-to-server communications (as in RFC 5766 and
+	RFC 6062). UDP supported only for relay communications. DTLS is not 
+	supported at all. The problem is in Winsock UDP sockets implementation.
+
+04/11/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.1.2 'Black Dow':
+
+	- Work on configuration and build.
+
+04/9/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.1.1 'Black Dow':
+
+	- Docs improvements.
+	- Load balancing use case added to TurnNetworks.pdf.
+	- Verbose mode split into 'normal' and 'extra' modes.
+	- Logging extended and fixed.
+
+04/7/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.1.0 'Black Dow':
+
+	- Compilation flags improved.
+	- utility programs renamed and moved to bin/ directory.
+	- README and turnserver man page separated into three sections -
+	turnserver, turnadmin, turnutils.
+
+04/6/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.0.6 'Black Dow':
+
+	- Added option "--psql-userdb" for better visual separation
+	between PostgreSQL and MySQL stuff.
+	- turnadmin flat files handling fixed.
+	- added set/show commands to turnadmin for secret key.
+
+04/6/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.0.5 'Black Dow':
+
+	- turnadmin MySQL connection fixed.
+	- minor cosmetic changes.
+	- Added "list" commands for long-term and short-term users,
+	 to turnadmin.
+
+04/5/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.0.4 'Black Dow':
+
+	- Minor compilation fixes.
+	- Minor docs fixes.
+	- "connect_timeout" option support for MySQL.
+
+04/5/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.0.3 'Black Dow':
+
+	- Issue 11 (secret timestamp check) fixed.
+
+04/4/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.0.2 'Black Dow':
+
+	- TCP sockets flush removed.
+	- rfc5769check utility removed from the Makefile.
+
+04/4/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.0.1 'Black Dow':
+
+	- Some short-term auth problems fixed.
+	- rfc5769check utility added to the Makefile and upgraded.
+
+04/3/2013 Oleg Moskalenko <[email protected]>
+Version 1.8.0.0 'Black Dow':
+
+	- Short-term credentials mechanism implemented.
+	
+04/2/2013 Oleg Moskalenko <[email protected]>
+Version 1.7.3.1 'Superior Glokta':
+
+	- Listeners code cleaned.
+	- The default number of extra relay threads changes from 0 to 1.
+
+04/1/2013 Oleg Moskalenko <[email protected]>
+Version 1.7.3.0 'Superior Glokta':
+
+	- Issue 10 fixed: log file control options.
+	  Two options added: --no-stdout-log and --log-file.
+
+03/29/2013 Oleg Moskalenko <[email protected]>
+Version 1.7.2.0 'Superior Glokta':
+
+	- Issue 9 fixed (uclient).
+	- Secret-based authentication implemented (see TURNServerRESTAPI.pdf).
+	- Uclient docs fixed.
+	- database schema extended (table for the secret added).
+
+03/27/2013 Oleg Moskalenko <[email protected]>
+Version 1.7.1.2 'Superior Glokta':
+
+	- CHANNEL BIND request handling fixed: now it produces an error
+		when client is trying to tie the same peer address to
+		different channels.
+	- uclient and peer test apps upgraded so that RTP channels
+		are talking  to <port> and RTCP channels are talking
+		to <port+1> in client-to-peer communication patterns.
+	- compilation warning is fixed when MySQL is not used.
+
+03/27/2013 Oleg Moskalenko <[email protected]>
+Version 1.7.1.1 'Superior Glokta':
+
+	- CONNECT response fixed in RFC 6062.
+	- uclient checks server responses integrity.
+
+03/26/2013 Oleg Moskalenko <[email protected]>
+Version 1.7.1.0 'Superior Glokta':
+
+	- MySQL support added for the user keys repository.
+	- PostgreSQL support improved.
+	- Docs fixed.
+	- 64 bits platform fixes.
+
+03/23/2013 Oleg Moskalenko <[email protected]>
+Version 1.7.0.0 'Glokta':
+
+	- Authentication fix.
+	- PostgreSQL database can be used as the user keys repository.
+
+03/21/2013 Oleg Moskalenko <[email protected]>
+Version 1.6.1.3 'Whirrun':
+
+	- UDP segmentation fault fixed
+
+03/21/2013 Oleg Moskalenko <[email protected]>
+Version 1.6.1.2 'Whirrun':
+
+	- RFC 6062 fix
+
+03/21/2013 Oleg Moskalenko <[email protected]>
+Version 1.6.1.1 'Whirrun':
+
+	- Authentication error fixed
+
+03/19/2013 Oleg Moskalenko <[email protected]>
+Version 1.6.1.0 'Whirrun':
+
+	- --stale-nonce option
+	- working on userdb
+	- "hang on" option fixed in uclient
+
+03/18/2013 Oleg Moskalenko <[email protected]>
+Version 1.6.0.2 'Whirrun':
+
+	- working on userdb
+	- c++ compilation fix
+
+03/17/2013 Oleg Moskalenko <[email protected]>
+Version 1.6.0.1 'Whirrun':
+
+	- uclient performance improved
+	- TurnNetworks.pdf document added
+
+03/15/2013 Oleg Moskalenko <[email protected]>
+Version 1.6.0.0 'Whirrun':
+
+	- "Pure" TCP relaying (RFC 6062) implemented.
+	- Network interactions fixes.
+	- RFC 6062 test scripts added.
+
+03/03/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.8 'Iosiv Lestek':
+
+	- authorization processing improvements.
+	- peer application fixed.
+	- some ICE attributes added.
+
+02/27/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.7 'Iosiv Lestek':
+
+	- authorization processing improvements
+	- Issue 4 fixed.
+	- secure client-to-client script added
+
+02/22/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.6 'Iosiv Lestek':
+
+	- strcpy/strncpy fixed
+	- some screen messages fixed
+	- uclient statistics fixed
+	- software attribute fixed
+	- example scripts fixed
+
+02/16/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.5 'Lestek':
+
+	- uclient application fixed
+	- Docs fixes
+
+02/14/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.4 'Lestek':
+
+	- Crash fixed on unconfigured interfaces
+	- Docs fixes
+
+02/12/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.3 'Lestek':
+
+	- Added feature: TURN Server always uses fingerprints in a session if
+	  the session client is using fingerprints.
+	- Default unsecure alternative port changed to 3479,
+	  default secure alternative port changed to 5350.
+	- TURN Server always trying to search for default certificate file
+	  turn_server_cert.pem and for default private key file
+	  turn_server_pkey.pem, if not certificate or private key is
+	  explicitly configured.
+	- configurable packet rate in the uclient test program.
+	- default peer port changed to 3480.
+	- -z, --no-auth option added to turnserver.
+
+02/11/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.2 'Lestek':
+
+	- Some cleanup added to the network input handlers.
+
+02/9/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.1 'Lestek':
+
+	- Binding requests do not require authentication.
+	- SOFTWARE in the end of the message.
+
+02/8/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.2.0 'Lestek':
+
+	- NAT discovery fixed (RFC5780).
+
+02/8/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.1.6 'Calder':
+
+	- Installation instructions fixed.
+
+02/8/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.1.5 'Calder':
+
+	- Mac compilation fixes.
+	- Fixes for old Linuxes.
+
+02/7/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.1.4 'Calder':
+
+	- Configuration alert (warning) messages.
+	- Relay addresses by default use listener addresses.
+	- Realm/user sequence fixed in the config file reading.
+
+01/27/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.1.3 'Calder':
+
+	- 'External' IP implemented for TURN-server-behind-NAT situation.
+
+01/26/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.1.2 'Calder':
+
+	- Alternative ports moved to 20000-ish territory.
+	- Docs fixes.
+
+01/22/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.1.1 'Calder':
+
+	- Docs fixes.
+
+01/22/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.1.0 'Calder':
+
+	- C++ compatible headers and build.
+	- C++ library header.
+	- HTML-formatted development reference.
+
+01/14/2013 Oleg Moskalenko <[email protected]>
+Version 1.5.0.0 'Calder':
+
+	- RFC 5769 check utility implemented.
+	- RFC 5780 STUN extension implemented.
+
+01/13/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.2.5 'Scale':
+
+	- Issue 2 fixed.
+
+01/08/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.2.4 'Scale':
+
+	- Bogus "Bind to device" error message removed (Linux).
+	- Docs improvements.
+
+01/08/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.2.3 'Scale':
+
+	- Bandwidth limitation implemented (--max-bps option).
+	- DTLS communications improved.
+
+01/07/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.2.2 'Scale':
+
+	- Output messages fixed.
+	- Peer test application accepts multiple listening addresses.
+	- config search directories improved.
+
+01/06/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.2.1 'Scale':
+
+	- Examples directory structure fixed
+	- Installation fixes
+	- Output messages fixed
+
+01/05/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.2 'Scale':
+
+	- Daemon execution improved
+	- Installation fixes
+	- Added comments to the scripts
+
+01/04/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.1.2 'Scale':
+
+	- Configure script introduced
+	- Installation fixes
+	- Run as daemon
+
+01/01/2013 Oleg Moskalenko <[email protected]>
+Version 1.4.1 'Scale':
+
+	- Options fixes
+	- Build fixes
+	- Script fixes
+	- Installation fixes
+
+12/31/2012 Oleg Moskalenko <[email protected]>
+Version 1.4 'Scale':
+
+	- Separate file for the dynamic user database
+	- Build fixes
+	- Script fixes
+	- Logging fixes
+
+12/29/2012 Oleg Moskalenko <[email protected]>
+Version 1.3.0.2 'Ferro':
+
+	- Debian 'squeeze' compilation fix
+
+12/26/2012 Oleg Moskalenko <[email protected]>
+Version 1.3.0.1 'Ferro':
+
+	- install procedure minor improvements
+
+12/24/2012 Oleg Moskalenko <[email protected]>
+Version 1.3 'Ferro':
+
+	- default conf file renamed to turnserver.conf
+	- build script improved
+	- client library linking fixed
+	- install procedure
+
+12/23/2012 Oleg Moskalenko <[email protected]>
+Version 1.2.3 'Luthar':
+
+	- turnserver options fixed
+	- man page renamed to turnserver
+
+12/22/2012 Oleg Moskalenko <[email protected]>
+Version 1.2.2:
+
+	- Man page fix
+
+12/21/2012 Oleg Moskalenko <[email protected]>
+Version 1.2.1 'Juvens':
+
+	- Man page
+
+12/21/2012 Oleg Moskalenko <[email protected]>
+Version 1.2 'Euz':
+
+	- Project cleaning
+
+12/20/2012 Oleg Moskalenko <[email protected]>
+Version 1.1 'no name':
+
+	- DTLS extension
+
+12/17/2012 Oleg Moskalenko <[email protected]>
+Version 1.0 'no name':
+
+	- RFC 5766
+	- RFC 6156

+ 963 - 0
INSTALL

@@ -0,0 +1,963 @@
+I. TURN Server as a standard OS package
+
+At the present time, several operation systems have this project pre-packaged:
+
+1) FreeBSD (and PC-BSD) have this project as a "port", named "turnserver",
+in /usr/ports/net/turnserver directory. Installation is very simple:
+
+# optional commands, to update the ports tree:
+  $ sudo portsnap fetch 
+  $ sudo portsnap update
+
+# Build and install the TURN Server: 
+  $ cd /usr/ports/net/turnserver
+  $ sudo make install clean
+  
+2) Debian "jessie" (and the recent version of Ubuntu and Mint)  
+have the predecessor of this project packaged as "rfc5766-turn-server", see the link:
+
+http://packages.qa.debian.org/r/rfc5766-turn-server.html
+
+In the new Debian "jessie", and in the related Ubuntu and Mint, you will 
+be able to just select rfc5766-turn-server from the packages list and 
+install it through Synaptic or through the package manager.
+
+3) ArchLinux has alse the predecessor of the TURN server package:
+
+https://aur.archlinux.org/packages/rfc5766-turn-server/
+
+4) OpenSUSE has a package, too:
+
+https://build.opensuse.org/package/show/home:ehauenstein/rfc5766-turn-server
+
+If you are using a pre-packaged TURN server then you can skip 
+to the section IX. 
+ 
+II. DOWNLOAD 
+
+You have to download the archive file turnserver-*.tar.gz and unpack it:
+
+$ tar xfz turnserver-*.tgz
+
+it will create the directory 'turnserver-*' with all sources, build files, 
+examples and documentation.
+
+III. BUILD
+
+If you are sure that you system is ready for the build (see the section 
+"Extra libraries and Utilities" below) then you can build the system.
+First, you have to run the configure script:
+
+	$ cd turnserver-*
+	$ ./configure
+	
+It will create a Makefile customized for your system. 
+
+By default, the generated Makefile will be set to install everything
+in:
+	- /usr on Solaris.
+	- /usr/pkg on NetBSD.
+	- /usr/local everywhere else.
+
+The binaries will be copied in bin subdirectory of the installation 
+destination, config files copied to etc subdirectory. There will be 
+also documents, examples and some other files, in separate directories.
+
+ You can change the root configured destination directory by 
+setting PREFIX variable in the 
+configure command line. For example:
+
+	$ PREFIX=/opt ./configure
+	
+Or:
+
+	$ ./configure --prefix=/opt   
+
+ You can change the auxiliary configured destination sub-directories by 
+setting BINDIR, CONFDIR, MANPREFIX, EXAMPLESDIR, DOCSDIR, LIBDIR, SCHEMADIR
+and TURNINCLUDEDIR variables in the 
+configure command line. For example:
+
+	$ PREFIX=/opt BINDIR=/opt/bin64 CONFDIR=/opt/conf ./configure
+	
+Or:
+
+	$ ./configure --prefix=/opt --bindir=/opt/bin64 --confdir=/opt/conf 
+
+ You also can change the compilation and link options by 
+setting common build variables in the 
+configure command line. For example:
+
+	$ CC=clang CFLAGS=-D_CAURIB LDFLAGS=-lshanka ./configure --prefix=/opt/shy
+
+See below a separate INSTALL section for more details.
+
+The script configure is a proprietary script. It will create a Makefile 
+that you can use to build the project:
+
+	$ make
+
+The make command without options will do the following:
+ - compile the code.
+ - create bin/ sub-directory and put the TURN server, TURN admin and 
+ "utility" programs there.
+ - create lib/ sub-directory and put the client library there.
+ - create include/turn/ sub-directory and put include files there.
+
+The programs can be either called directly, or a shell scripts can be used. 
+The script examples are located in examples/scripts directory. These scripts 
+are just examples: you can run them successfully for the tests, but
+you will have to change the script parameters for your real environment.
+
+The command:
+
+	$ sudo make install 
+
+will install everything into the system file structure (see below).
+
+(NOTE: On NetBSD, use "su root -c").
+
+The command:
+
+	$ sudo make deinstall
+	
+will remove all installed TURN Server files from your system.
+
+The command:
+
+	$ make clean 
+	
+will clean all results of the build and configuration actions.
+
+Do not run "make clean" before "make deinstall". The "clean" command will
+remove the Makefile and you will not be able to "deinstall" then. If that 
+has happened, then run ./configure and make again, then deinstall and then 
+clean.
+
+NOTE: On most modern systems, the build will produce dynamically linked 
+executables. If you want statically linked executables, you have to modify, 
+accordingly, the Makefile.in template file.
+
+IV. INSTALL
+
+This step is optional. You can run the turnserver from the original build 
+directory, successfully, without installing the TURN server into the system. 
+You have to install the turnserver only if you want to integrate the 
+turnserver in your system.
+
+Run the command:
+
+$ make install
+
+It will install turnserver in /usr/local/ directory (or to whatever directory
+was set in the PREFIX variable). You will have to copy 
+/usr/local/etc/turnserver.conf.default to /usr/local/etc/turnserver.conf file 
+and adjust your runtime configuration.
+
+This command will also:
+
+ - copy the content of examples subdirectory into 
+ PREFIX/share/examples/turnserver/ directory;
+ - copy the content of include/turn subdirectory into
+ PREFIX/include/turn/ directory;
+ - copy the database schema file turndb/schema.sql into 
+ PREFIX/share/turnserver/ 
+ directory;
+ - copy all docs into PREFIX/share/doc/turnserver/ directory.
+ 
+The installation destination of "make install" can be changed by
+using DESTDIR variable, for example:
+
+ $ ./configure --prefix=/usr
+ $ make
+ $ make DESTDIR=/opt install
+ 
+In this example, the root installation directory will be /opt/usr.  
+
+The "configure" script by default generates a Makefile with "rpath" option
+set for the binaries linking (if your compiler allows that option). If that 
+is not desirable (like in some OS packaging procedures), then run the 
+"configure" script with --disable-rpath option.
+
+If you do not want to use the rpath linking option, or you OS or compiler 
+do not allows that, then after the installation, you may have to adjust the 
+system-wide shared library search path by using "ldconfig -n <libdirname>" 
+(Linux), "ldconfig -m <libdirname>" (BSD) or "crle -u -l <libdirname>" 
+(Solaris). Your system must be able to find the libevent2, openssl and 
+(optionally) PostgreSQL and/or MySQL (MariaDB) and/or Redis shared libraries, 
+either with the help of the system-wide library search configuration or by 
+using LD_LIBRARY_PATH. "make install" will make a non-garantied effort to add 
+automatically PREFIX/lib and /usr/local/lib to the libraries search path, 
+but if you have some libraries in different non-default directories 
+you will have to add them manually to the search path, or you 
+will have to adjust LD_LIBRARY_PATH.
+
+V. PLATFORMS
+
+The TURN Server is using generic *NIX system APIs and is supposed to be 
+usable on wide range of *NIX systems. 
+
+The following platforms have been used in the development:
+
+	- Linux Ubuntu 11.x and 12.x, i386 and x86_64
+	- FreeBSD 6.x, i386
+	- FreeBSD 8.x, i386
+	- PC-BSD 9.x, x86_64
+	- Solaris 11, x86_64
+	- Linux CentOS / Red Hat Enterprise Edition 6.3, x86_64 (amd64)
+	- Linux CentOS / Red Hat Enterprise Edition 6.4, x86_32 (i386)
+	- Linux Debian 'Squeeze', i386
+	- Linux Mint 14.1 'Nadia', i386
+	- Linux Debian 'Wheezy', x86_64 
+	- Cygwin 1.7.20
+	- NetBSD 6.0.1
+	- OpenBSD 5.3
+	- Amazon Linux
+	- Mac OS X Mountain Lion
+	- ArchLinux
+	- Fedora 19
+	- OpenSUSE 12.3 x86_64
+
+It must work on many other *NIXes, as well. The configure script and/or 
+Makefile may need adjustments for other *NIXes not mentioned above.
+
+The code of the client messaging library can be compiled and used on 
+Windows, too, but it is not supported for now.
+
+VI. COMPILERS
+
+The TURN Server is written in C programming language, for portability 
+and for the performance reasons. 
+
+The tested C compilers are:
+
+	- gcc 3.4.4 thru 4.8.1
+	- clang 3.0 or better
+	- Solaris Studio 12.3 C compiler, version 5.12
+
+It may be compiled with others compilers, too.
+
+The code is compatible with C++ compiler, and a C++ compiler
+(like g++) can be used for the compilation, too:
+
+	$ CC=g++ ./configure
+	$ make
+
+VII. WHICH EXTRA LIBRARIES AND UTILITIES YOU NEED 
+
+In addition to common *NIX OS services and libraries, to compile this code, 
+OpenSSL (version 1.0.0a or better recommended) and libevent2 (version 2.0.5 
+or better) are required, the PostgreSQL C client development setup is 
+optional, the MySQL (MariaDB) C client development setup is optional, and the 
+Hiredis development files for Redis database access are optional.
+For fully functional build, the extra set of libraries must be installed
+in full version (the development headers and the libraries to link with). 
+For runtime, only runtime setup is required. If the build is modified for 
+static linking, then even runtime installation is not needed.
+
+OpenSSL, libevent2, PostgreSQL, MySQL (or MariaDB) and Hiredis 
+libraries can be downloaded from their web sites:
+ - http://www.openssl.org (required);
+ - http://www.libevent.org (required);
+ - http://www.postgresql.org (optional);
+ - http://www.mysql.org (or http://mariadb.org) (optional);
+ - http://redis.io (optional).
+ 
+The installations are pretty straightforward - the usual 
+"./configure" and "make install" commands. Install them into their default 
+locations - the configure script and the Makefile are assuming that they are 
+installed in their default locations. If not, then you will have to modify 
+those.
+
+Most modern popular systems (FreeBSD / PC-BSD, Linux Ubuntu 11.10+, Debian Wheezy, 
+Linux Mint 14+, Amazon Linux, Fedora) have a simpler way of the third party tools 
+installation:      
+
+	*) PC-BSD or FreeBSD (the FRESH ports database is assumed to be installed, with
+		the turnserver port included):
+
+		$ cd /usr/ports/net/turnserver
+		$ sudo make install clear
+
+		That's it - that command will install the TURN server with all necesary
+		thrid-party tools.
+
+		If you system have no fresh ports repository:
+
+		$ cd /usr/ports/security/openssl/
+		$ sudo make install clean
+		$ cd /usr/ports/devel/libevent2/
+		$ sudo make install clean
+		$ cd /usr/ports/databases/postgresql84-client/ (or any other version)
+		$ sudo make install clean
+		$ cd /usr/ports/databases/mysql51-client/ (or any other version)
+		$ sudo make install clean
+		$ cd /usr/ports/databases/hiredis/
+		$ sudo make install clean
+
+	**) Linux Ubuntu 11.10+, Debian Wheezy, Mint 14+:
+		
+		$ sudo apt-get install libssl-dev
+		$ sudo apt-get install libevent-dev
+		$ sudo apt-get install libpq-dev
+		$ sudo apt-get install mysql-client
+		$ sudo apt-get install libmysqlclient-dev
+		$ sudo apt-get install libhiredis-dev
+		
+		or you can use Synaptic or other software center.
+
+	***) Fedora:
+
+	$ sudo yum install openssl-devel
+	$ sudo yum install libevent
+	$ sudo yum install libevent-devel
+	$ sudo yum install postgresql-devel
+	$ sudo yum install postgresql-server
+	$ sudo yum install mysql-devel
+	$ sudo yum install mysql-server
+	$ sudo yum install hiredis
+	$ sudo yum install hiredis-devel
+
+	****) Amazon Linux is similar to Fedora, but:
+
+	- you have to install gcc first:
+		$ sudo yum install gcc
+
+	- hiredis packages are not available, so do not issue the 
+	hiredis installation commands. Redis support will not be 
+	compiled, unless you install it "manually" before the TURN 
+	server compilation. For Amazon EC2 AMIs, we install the 
+	redis manually in the system. But the TURN server can be 
+	perfectly installed without redis support - if you do not 
+	need it.
+		
+	*****) Some OSes in Debian family (Debian Squeeze and 
+	pre-11.10 Ubuntus) setups are similar to Debian Wheezy, 
+	although some packages have different names. 
+		 
+	******) On some CentOS / RedHat 6.x systems you have to install 
+	libevent2 "manually", and optionally you have to download and 
+	install Hiredis, but everything else can be found in the software 
+	repository. Also, if you would like to make an RPM for CentOS,
+	check the directory rpm/ with the instructions.
+
+NOTE: If your tools are installed in non-standard locations, you will 
+have to adjust CFLAGS and LDFLAGS environment variables for TURN 
+server ./configure script. For example, to configure the TURN server 
+with Solaris 11 PostgreSQL 32-bits setup, you may use a command 
+like this:
+
+  $ CFLAGS="${CFLAGS} -I/usr/postgres/9.2-pgdg/include/" LDFLAGS="${LDFLAGS} -L/usr/postgres/9.2-pgdg/lib/" ./configure
+
+Dynamic library paths:
+
+You may also have to adjust the turn server start script, add PostgreSQL 
+and/or MySQL and/or Redis runtime library path to LD_LIBRARY_PATH. 
+Or you may find that it would be more convenient to adjust the 
+system-wide shared library search path by using commands:
+
+on Linux:
+
+  $ ldconfig -n <libdirname> 
+
+or on BSD:
+
+  $ ldconfig -m <libdirname>
+
+or on Solaris:
+
+  $ crle -u -l <libdirname>
+
+On Mac OS X, you have three different choices for dynamic libraries handling:
+
+1) Use DYLD_LIBRARY_PATH environment variable in runtime; OR
+
+2) Before the compilation, check the dynamic libraries and adjust their identification names,
+if necessary, to the absolute library path or to @rpath/<library-file-name>. 
+For exmple, the MySQL dynamic library may need that adjustment. You will have to use 
+"adjust_name_tool" with -id option for that; OR
+
+3) After the compilation, you can use the same tool, "adjust_name_tool", with option -change,
+to adjust the library paths values in the binary, where necessary. All library paths must be 
+absolute paths or @rpath/... .
+
+See also the next section.
+
+NOTE: See "PostgreSQL setup" and "MySQL setup" and "Redis setup" sections 
+below for more database setup information.
+
+NOTE: If you do not install PostgreSQL or MySQL or Redis then you will
+be limited to flat files for user database. It will work great for 
+smaller user databases (like 100 users) but for larger systems you 
+will need PostgreSQL or MySQL or Redis.
+
+NOTE: To run PostgreSQL or MySQL or Redis server on the same system, 
+you will also have to install a corresponding PostgreSQL or MySQL or 
+Redis server package. The DB C development packages only provide 
+development libraries, and client libraries only provide client 
+access utilities and runtime libraries. The server packages may 
+include everything - client, C development and server runtime.   
+
+NOTE: OpenSSL to be installed before libevent2. When libevent2 is building, 
+it is checking whether OpenSSL has been already installed, and which version 
+of OpenSSL. If the OpenSSL is missed, or too old, then libevent_openssl 
+library is not being created during the build, and you will not be able to 
+compile the TURN Server with TLS support.
+
+NOTE: An older libevent version, version 1.x.x, is often included in some *NIX 
+distributions. That version has its deficiencies and is inferior to the newer 
+libevent2, especially in the performance department. This is why we are 
+not providing backward compatibility with the older libevent 1.x version. 
+If you have a system with older libevent, then you have to install the new 
+libevent2 from their web site. It was tested with older *NIXes 
+(like FreeBSD 6.x) and it works just fine.
+
+NOTE: For extra security features (DTLS and SHA256) support, OpenSSL version 
+1.0.0a or newer is recommended. Older versions do not support DTLS, reliably, 
+in some cases. For example, the Debian 'Squeeze' Linux supplies 0.9.8 version 
+of OpenSSL, that does not work correctly with DTLS over IPv6. If your system 
+already has an older version of OpenSSL installed (usually in directory /usr) 
+then you may want to install your newer OpenSSL "over" the old one (because it 
+will most probably will not allow removal of the old one). When installing 
+the newer OpenSSL, run the OpenSSL's configure command like this:
+
+    $ ./config --prefix=/usr
+
+that will set the installation prefix to /usr (without "--prefix=/usr" 
+by default it would be installed to /usr/local). This is necessary if you 
+want to overwrite your existing older OpenSSL installation.
+
+VIII. BUILDING WITH NON-DEFAULT PREFIX DIRECTORY
+
+Say, you have an older system with old openssl and old libevent 
+library and you do not want to change that, but you still want 
+to build the turnserver.
+
+Do the following steps:
+
+1) Download new openssl from openssl.org.
+2) Configure and build new openssl and install it into /opt:
+  
+    $ ./config --prefix=/opt
+    $ make
+    $ make install
+
+3) Download the latest libevent2 from libevent.org, configure and install 
+it into /opt:
+
+    $ ./configure --prefix=/opt
+    $ make
+    $ make install
+
+4) Change directory to coturn and build it:
+
+    $ ./configure --prefix=/opt
+    $ make
+
+After that, you can either use it locally, or install it into /opt. 
+But remember that to run it, you have to adjust your LD_LIBRARY_PATH, 
+like that:
+
+    $ LD_LIBRARY_PATH=/opt/lib ./bin/turnserver
+
+An alternative would be adjusting the system-wide shared library search path 
+by using 
+ $ ldconfig -n <libdirname> (Linux) 
+ $ ldconfig -m <libdirname> (BSD) 
+ $ crle -u -l <libdirname> (Solaris)
+
+IX. TEST SCRIPT SETS
+
+First of all, we can use test vectors from RFC 5769 to double-check that our 
+STUN/TURN message encoding algorithms work properly. Run the utility:
+
+ $ cd examples
+ $ ./scripts/rfc5769.sh
+ 
+It will perform several protocol checks and print the results on the output. 
+If anything has compiled wrongly (TURN Server, or OpenSSL libraries) 
+then you will see some errors.
+
+Now, you can perform the TURN functionality test (bare minimum TURN example).
+
+If everything compiled properly, then the following programs must run 
+together successfully, simulating TURN network routing in local loopback
+networking environment:
+
+Open two shell screens or consoles:
+
+In shell number 1, run TURN server application:
+ $ cd examples
+ $ ./scripts/basic/relay.sh
+
+In shell number 2, run test client application:
+
+ $ cd examples
+ $ ./scripts/basic/udp_c2c_client.sh
+
+If the client application produces output and in approximately 22 seconds 
+prints the jitter, loss and round-trip-delay statistics, then everything is 
+fine.
+
+There is another more complex test:
+
+In shell number 1, run TURN server application:
+ $ cd examples
+ $ ./scripts/basic/relay.sh
+ 
+In shell number 2, run "peer" application:
+ $ cd examples
+ $ ./scripts/peer.sh
+
+In shell number 3, run test client application:
+
+ $ cd examples
+ $ ./scripts/basic/udp_client.sh (or ./scripts/basic/tcp_client.sh)
+
+There is a similar set of examples/scripts/longtermsecure/* scripts for 
+TURN environment with long-term authentication mechanism. This set of 
+scripts is more complex, and checking the scripts options is useful for 
+understanding how the TURN Server works:
+
+In shell number 1, run secure TURN server application:
+ $ cd examples
+ $ ./scripts/longtermsecure/secure_relay.sh
+ 
+In shell number 2, run "peer" application:
+ $ cd examples
+ $ ./scripts/peer.sh
+
+In shell number 3, run secure test client application:
+
+ $ cd examples
+ $ ./scripts/longtermsecure/secure_udp_client.sh
+  
+ (or ./scripts/longtermsecure/secure_tcp_client.sh)
+ (or ./scripts/longtermsecure/secure_tls_client.sh)
+ (or ./scripts/longtermsecure/secure_dtls_client.sh)
+ (or ./scripts/longtermsecure/secure_udp_c2c.sh for "peerless" 
+client-to-client communications)
+
+The provided scripts are set for the local loopback communications, 
+as an example and as a test environment. Real networking IPs must be 
+used in real work environments. 
+
+Try wireshark to check the communications between client, turnserver 
+and the peer. 
+
+Check the README.* files and the comments in the scripts relay.sh and 
+secure_relay.sh as a guidance how to run the TURN server.
+
+X. OS X compilation notes
+
+OS X usually has an older version of openssl supplied, with some Apple 
+additions. The best option is to install a good fresh openssl development 
+library, free of Apple tweaks, from http://www.openssl.org. But the "native"
+openssl will work, too.
+
+XI. MS Windows and Cygwin support
+
+Currently, this project cannot be compiled under MS Windows.
+
+As the project is using fairly straightforward *NIX API, it is supported 
+under Cygwin environment in MS Windows.
+
+One note for Cygwin users: we recommended libevent2 installation from the cygwin
+"ports" site: http://sourceware.org/cygwinports/ . You will have to install 
+libevent2 runtime and libevent-devel packages. "Manual" libevent2 compilation
+and installation in Cygwin is not recommended and does not garantee a good 
+outcome.
+
+XII. CLIENT API LIBRARY.
+
+The compilation process will create lib/ sub-directory with libturnclient.a 
+library. The header files for this library are located in include/turn/client/ 
+sub-directory. The C++ wrapper for the messaging functionality is located in 
+TurnMsgLib.h header. An example of C++ code can be found in stunclient.c file. 
+This file is compiled as a C++ program if C++ compiler is used, and as a C 
+program if C compiler is used.
+
+XIII. DOCS
+
+After installation, the man page turnserver(1) must be available. The man page 
+is located in man/man1 subdirectory. If you want to see the man page without 
+installation, run the command:
+
+	$	man -M man turnserver
+
+HTML-formatted client library functions reference is located in docs/html 
+subdirectory of the original archive tree. After the installation, it will 
+be placed in PREFIX/share/doc/turnserver/html.
+
+XIV. PostgreSQL setup
+
+The site http://www.postgresql.org site has excellent extensive documentation. 
+For a quick-start guide, you can take a look into this page: 
+http://www.freebsddiary.org/postgresql.php. That page is written for 
+FreeBSD users, but it has lots of generic information applicable to other 
+*NIXes, too.
+
+For the psql-userdb TURN server parameter, you can either set a PostgreSQL 
+connection string, or a PostgreSQL URI, see the link:
+
+For 8.4 PostgreSQL version:
+http://www.postgresql.org/docs/8.4/static/libpq-connect.html
+
+For newer 9.x versions: 
+http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-CONNSTRING.
+
+In the PostgreSQL connection string or URI, you can set the host, the 
+access port, the database name, the user, and the user password 
+(if the access is secured). Numerous other parameters can be set, 
+see the links above. The TURN server will blindly use that connection 
+string without any modifications. You are responsible for the right 
+connection string format.
+
+Below are the steps to setup the PostgreSQL database server from scratch:
+
+1) Install PostgreSQL server.
+
+2) Find and edit Postgres' pg_hba.conf file to set the access options 
+(see docs). On different systems, it may be located in different places.
+Set the lines for local access as "trust" for now (you can change it later), 
+for TCP/IP access set the value as "md5".
+To set TCP/IP access from any host, use "0.0.0.0/0" for IPv4, and "::/0" 
+for IPv6.
+
+3) Edit postgresql.conf file to allow TCP/IP access - uncomment and edit 
+the "listen_addresses" option (see docs). On different systems, this file 
+may be located in different places.
+
+4) Restart your system or restart the postgresql server, for example:
+
+  $ sudo /etc/init.d/postgresql stop
+  $ sudo /etc/init.d/postgresql start
+
+5) Check /etc/passwd file to find out which user account is used for the 
+PostgreSQL admin access on your system (it may be "pgsql", or "postgres", 
+or "postgresql"). Let's assume that this is "postgres" account.
+
+6) Create a database for the TURN purposes, with name, say, "turn":
+
+   $ createdb -U postgres turn
+
+7) Create a user for the TURN with name, say, "turn":
+   $ psql -U postgres turn
+     turn=# create user turn with password 'turn';
+     turn=# 
+     Ctrl-D
+
+8) Create the TURN users database schema.
+
+The database schema for the TURN server is very minimalistic and is located 
+in project's turndb/schema.sql file, or in the system's 
+PREFIX/share/turnserver/schema.sql file after the turnserver installation:
+
+$ cat turndb/schema.sql | psql -U turn turn
+	NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "turnusers_lt_pkey" for table "turnusers_lt"
+	CREATE TABLE
+	NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "turnusers_st_pkey" for table "turnusers_st"
+	CREATE TABLE
+	CREATE TABLE
+$ 
+
+The schema description:
+
+# Table for long-term credentials mechanism authorization:
+#
+CREATE TABLE turnusers_lt (
+    realm varchar(512),
+    name varchar(512),
+    hmackey char(128),
+    PRIMARY KEY (realm,name)
+);
+
+# Table for short-term credentials mechanism authorisation:
+#
+CREATE TABLE turnusers_st (
+    name varchar(512) PRIMARY KEY,
+    password varchar(512)
+);
+
+# Table holding shared secrets for secret-based authorization
+# (REST API). It can only be used together with the long-term 
+# mechanism:
+#
+CREATE TABLE turn_secret (
+	realm varchar(512),
+    value varchar(512),
+	primary key (realm,value)
+);
+
+# Table holding "white" allowed peer IP ranges.
+#
+CREATE TABLE allowed_peer_ip (
+	ip_range varchar(256),
+	primary key (ip_range)
+);
+
+# Table holding "black" denied peer IP ranges.
+#
+CREATE TABLE denied_peer_ip (
+	ip_range varchar(256),
+	primary key (ip_range)
+);
+
+# Table to match origin to realm.
+# Multiple origins may have the same realm.
+# If no realm is found or the origin is absent
+# then the default realm is used.
+#
+CREATE TABLE turn_origin_to_realm (
+	origin varchar(512),
+	realm varchar(512),
+	primary key (origin,realm)
+);
+
+# Realm options.
+# Valid options are 'max-bps',
+# 'total-quota' and 'user-quota'.
+# Values for them are integers (in text form).
+#
+CREATE TABLE turn_realm_option (
+	realm varchar(512),
+	opt varchar(32),
+	value varchar(128),
+	primary key (realm,opt)
+);
+
+The field hmackey contains HEX string representation of the key.
+We do not store the user open passwords for long-term credentials, for security reasons.
+Storing only the HMAC key has its own implications - if you change the realm,
+you will have to update the HMAC keys of all users, because the realm is 
+used for the HMAC key generation.
+
+The key must be 32 characters (HEX representation of 16 bytes) for SHA1,
+or 64 characters (HEX representation of 32 bytes) for SHA256.
+
+You can use turnadmin program to manage the database - you can either use 
+turnadmin to add/modify/delete users, or you can use turnadmin to produce 
+the hmac keys and modify the database with your favorite tools.
+
+More examples of database schema creation:
+
+psql -h <host> -U <db-user> -d <database-name>  < turndb/schema.sql
+(old style for 8.4)
+
+psql postgresql://username:password@/databasename < turndb/schema.sql
+(newer style for 9.x, UNIX domain local sockets)
+
+Or:
+
+psql postgresql://username:password@hostname:port/databasename < turndb/schema.sql
+(newer style for 9.x, TCP/IP access)
+
+Below, the string "postgresql://turn:turn@/turn" is the connection URI. 
+Of course, the administrators can play with the connection string as they want.
+
+When starting the turnserver, the psql-userdb parameter will be, for example:
+
+turnserver ... --psql-userdb="host=localhost dbname=turn user=turn password=turn connect_timeout=30"
+
+Or, for 9.x PostgreSQL versions: 
+turnserver ... --psql-userdb=postgresql://username:password@/databasename ...
+
+9) You are ready to use the TURN database. The database name is "turn",
+the user name is "turn", the user password is "turn". Of course, you can 
+choose your own names. Now, you will have to use the program turnadmin to fill the 
+database, or you can do that manually with psql.
+
+Fill in users, for example:
+
+  Shared secret for the TURN REST API:
+  
+  $ bin/turnadmin -s logen -e "host=localhost dbname=turn user=turn password=turn"
+  
+  Long-term credentials mechanism:
+  
+  $ bin/turnadmin -a -e "host=localhost dbname=turn user=turn password=turn" -u gorst -r north.gov -p hero
+  $ bin/turnadmin -a -e "host=localhost dbname=turn user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic
+  
+  Long-term credentials mechanism with SHA256 extention:
+  $ bin/turnadmin -a -e "host=localhost dbname=turn user=turn password=turn" -u bethod -r north.gov -p king-of-north --sha256
+  
+  Short-term credentials mechanism:
+   
+  $ bin/turnadmin -A -e "host=localhost dbname=turn user=turn password=turn" -u gorst -r north.gov -p hero
+  $ bin/turnadmin -A -e "host=localhost dbname=turn user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic 
+
+XV. MySQL (MariaDB) setup
+
+The MySQL setup is similar to PostgreSQL (same idea), and is well documented 
+on their site http://www.mysql.org. The TURN Server database schema is the 
+same as for PostgreSQL and you can find it in turndb/schema.sql file, or 
+in the system's PREFIX/share/turnserver/schema.sql file after the turnserver 
+installation.
+
+The general setup idea is the same as for PostgreSQL case:
+
+1) Check that the mysql server access is OK. Immediately after the MySQL server 
+installation, it must be accessible, at the very minimum, at the localhost with
+the root account.
+
+2) Login into mysql console from root account:
+
+  $ sudo bash
+  # mysql -p mysql
+  
+3) Add 'turn' user with 'turn' password (for example):
+
+  > create user 'turn'@'localhost' identified by 'turn';
+  
+4) Create database 'turn' (for example) and grant privileges to user 'turn':
+
+  > create database turn;
+  > grant all on turn.* to 'turn'@'localhost';
+  > flush privileges;
+  Ctrl-D
+  
+5) Create database schema:
+
+  $ mysql -p -u turn turn < turndb/schema.sql
+  Enter password: turn
+  $
+  
+6) Fill in users, for example:
+
+  Shared secret for the TURN REST API:
+  
+  $ bin/turnadmin -s logen -M "host=localhost dbname=turn user=turn password=turn"
+  
+  Long-term credentials mechanism:
+  
+  $ bin/turnadmin -a -M "host=localhost dbname=turn user=turn password=turn" -u gorst -r north.gov -p hero
+  $ bin/turnadmin -a -M "host=localhost dbname=turn user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic
+  
+  Long-term credentials mechanism with SHA256 extention:
+  $ bin/turnadmin -a -M "host=localhost dbname=turn user=turn password=turn" -u bethod -r north.gov -p king-of-north --sha256
+  
+  Short-term credentials mechanism:
+   
+  $ bin/turnadmin -A -M "host=localhost dbname=turn user=turn password=turn" -u gorst -r north.gov -p hero
+  $ bin/turnadmin -A -M "host=localhost dbname=turn user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic 
+
+7) Now we can use mysql in the turnserver.
+
+If the TURN server was compiled with MySQL support, then we can use the 
+TURN server database parameter --mysql-userdb. The value of this parameter 
+is a connection string for the MySQL database. As "native" MySQL does not 
+have such a feature as "connection string", the TURN server parses the 
+connection string and converts it into MySQL database connection parameter. 
+The format of the MySQL connection string is:
+
+"host=<host> dbname=<database-name> user=<database-user> password=<database-user-password> port=<port> connect_timeout=<seconds>"
+
+(all parameters are optional)
+
+So, an example of the MySQL database parameter in the TURN server command 
+line would be:
+
+--mysql-userdb="host=localhost dbname=turn user=turn password=turn connect_timeout=30"
+
+Or in the turnserver.conf file:
+
+mysql-userdb="host=localhost dbname=turn user=turn password=turn connect_timeout=30"
+
+XVI. Redis setup
+
+The Redis setup is well documented on their site http://redis.io. 
+The TURN Server Redis database schema description can be found 
+in schema.userdb.redis and schema.stats.redis files. Those files are located
+either in the turndb subdirectory of the main source code directory,
+or in /usr/local/share/turnserver/ after the installation, or somewhere in /usr/share/
+directory, depending on the OS and on the instalation package.
+
+If the TURN server was compiled with Hiredis support (Hiredis is the C client 
+library for Redis), then we can use the TURN server database parameter 
+--redis-userdb. The value of this parameter is a connection string 
+for the Redis database. As "native" Redis does not have such a feature as 
+"connection string", the TURN server parses the connection string and 
+converts it into Redis database access parameter. The format of the Redis 
+connection string is:
+
+"ip=<ip-addr> dbname=<database-number> password=<database-password> port=<port> connect_timeout=<seconds>"
+
+(all parameters are optional)
+
+So, an example of the Redis database parameter in the TURN server command 
+line would be:
+
+--redis-userdb="ip=127.0.0.1 dbname=0 password=turn connect_timeout=30"
+
+Or in the turnserver.conf file:
+
+redis-userdb="ip=127.0.0.1 dbname=0 password=turn connect_timeout=30"
+
+Redis can be also used for the TURN allocation status check and for status and 
+traffic notifications.
+
+See the explanation in the turndb/schema.stats.redis file, and an example in 
+turndb/testredisdbsetup.sh file. One special thing about TURN Redis security setup
+is that you can store open passwords for long-term credentials in Redis.
+You cannot set open passwords for long-term credentials in MySQL and PostgreSQL -
+with those DBs, you have to use the keys only. With Redis, you have a choice - 
+keys or open passwords.
+
+You also have to take care about Redis connection parameters, the timeout and the 
+keepalive. The following settings must be in your Redis config file
+(/etc/redis.conf or /usr/local/etc/redis.conf):
+
+..........
+timeout 0
+..........
+tcp-keepalive 60
+..........
+
+Redis TURN admin commands:
+
+  Shared secret for the TURN REST API:
+  
+  $ bin/turnadmin -s logen -N "host=localhost dbname=0 user=turn password=turn"
+  
+  Long-term credentials mechanism:
+  
+  $ bin/turnadmin -a -N "host=localhost dbname=0 user=turn password=turn" -u gorst -r north.gov -p hero
+  $ bin/turnadmin -a -N "host=localhost dbname=0 user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic
+  
+  Long-term credentials mechanism with SHA256 extention:
+  $ bin/turnadmin -a -N "host=localhost dbname=0 user=turn password=turn" -u bethod -r north.gov -p king-of-north --sha256
+  
+  Short-term credentials mechanism:
+   
+  $ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u gorst -r north.gov -p hero
+  $ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic 
+
+XV. Performance tuning
+
+This topic is covered in the wiki page:
+
+http://code.google.com/p/coturn/wiki/turn_performance_and_load_balance
+
+XVI. TURN Server setup
+
+Read the project wiki pages: http://code.google.com/p/coturn/w/list
+
+Also, check the project from page links to the TURN/WebRTC configuration examples.
+It may give you an idea how it can be done.
+
+XVI. Management interface
+
+You have a telnet interface (enabled by default) to access the turnserver process, 
+to view its state, to gather some statistical information, and to make some changes 
+on-the-fly.
+
+You can access that CLI interface with telnet or putty program (in telnet mode). 
+The process by default listens to port 5766 on IP address 127.0.0.1 for the telnet
+connections. 
+
+WARNING: all telnet communications are going unencrypted over the network. For
+security reasons, we advise using the loopback IP addresses for CLI (127.0.0.1 
+or ::1). The CLI may have a password configured, but that password is
+transferred over the network unencrypted, too. So sticking to the local system
+CLI access, and accessing the turnserver system terminal with ssh only, would 
+be a wise decision.

+ 31 - 0
LICENSE

@@ -0,0 +1,31 @@
+/*
+ * TURN Server - RFC5766 TURN Server implementation
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+

+ 127 - 0
LICENSE.OpenSSL

@@ -0,0 +1,127 @@
+
+  LICENSE ISSUES
+  ==============
+
+  The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
+  the OpenSSL License and the original SSLeay license apply to the toolkit.
+  See below for the actual license texts. Actually both licenses are BSD-style
+  Open Source licenses. In case of any license issues related to OpenSSL
+  please contact [email protected].
+
+  OpenSSL License
+  ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2008 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    [email protected].
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * ([email protected]).  This product includes software written by Tim
+ * Hudson ([email protected]).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young ([email protected])
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young ([email protected]).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson ([email protected]).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young ([email protected])"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson ([email protected])"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+

+ 173 - 0
Makefile.in

@@ -0,0 +1,173 @@
+
+LIBEVENT_INCLUDE = -I${PREFIX}/include/ -I/usr/local/include/
+
+INCFLAGS = -Isrc -Isrc/apps/common -Isrc/server -Isrc/client -Isrc/client++ ${LIBEVENT_INCLUDE} 
+
+CFLAGS += ${INCFLAGS}
+
+MAKE_DEPS = Makefile
+
+LIBCLIENTTURN_HEADERS = src/ns_turn_defs.h src/client++/TurnMsgLib.h src/client/ns_turn_ioaddr.h src/client/ns_turn_msg.h src/client/ns_turn_msg_defs.h src/client/ns_turn_msg_addr.h
+LIBCLIENTTURN_MODS = src/client/ns_turn_ioaddr.c src/client/ns_turn_msg_addr.c src/client/ns_turn_msg.c 
+LIBCLIENTTURN_DEPS = ${LIBCLIENTTURN_HEADERS} ${MAKE_DEPS} 
+LIBCLIENTTURN_OBJS = build/obj/ns_turn_ioaddr.o build/obj/ns_turn_msg_addr.o build/obj/ns_turn_msg.o 
+
+SERVERTURN_HEADERS = src/server/ns_turn_allocation.h src/server/ns_turn_ioalib.h src/server/ns_turn_khash.h src/server/ns_turn_maps_rtcp.h src/server/ns_turn_maps.h src/server/ns_turn_server.h src/server/ns_turn_session.h 
+SERVERTURN_DEPS = ${LIBCLIENTTURN_HEADERS} ${SERVERTURN_HEADERS} ${MAKE_DEPS} 
+SERVERTURN_MODS = ${LIBCLIENTTURN_MODS} src/server/ns_turn_allocation.c src/server/ns_turn_maps_rtcp.c src/server/ns_turn_maps.c src/server/ns_turn_server.c
+
+COMMON_HEADERS = src/apps/common/apputils.h src/apps/common/ns_turn_utils.h src/apps/common/stun_buffer.h
+COMMON_MODS = src/apps/common/apputils.c src/apps/common/ns_turn_utils.c src/apps/common/stun_buffer.c
+COMMON_DEPS = ${LIBCLIENTTURN_DEPS} ${COMMON_MODS} ${COMMON_HEADERS}
+
+IMPL_HEADERS = src/apps/relay/ns_ioalib_impl.h src/apps/relay/ns_sm.h src/apps/relay/turn_ports.h
+IMPL_MODS = src/apps/relay/ns_ioalib_engine_impl.c src/apps/relay/turn_ports.c
+IMPL_DEPS = ${COMMON_DEPS} ${IMPL_HEADERS} ${IMPL_MODS}
+
+HIREDIS_HEADERS = src/apps/common/hiredis_libevent2.h
+HIREDIS_MODS = src/apps/common/hiredis_libevent2.c
+
+SERVERAPP_HEADERS = src/apps/relay/userdb.h src/apps/relay/tls_listener.h src/apps/relay/mainrelay.h src/apps/relay/turncli.h src/apps/relay/dtls_listener.h src/apps/relay/libtelnet.h ${HIREDIS_HEADERS}
+SERVERAPP_MODS = src/apps/relay/mainrelay.c src/apps/relay/netengine.c src/apps/relay/libtelnet.c src/apps/relay/turncli.c src/apps/relay/userdb.c src/apps/relay/tls_listener.c src/apps/relay/dtls_listener.c ${HIREDIS_MODS}
+SERVERAPP_DEPS = ${SERVERTURN_MODS} ${SERVERTURN_DEPS} ${SERVERAPP_MODS} ${SERVERAPP_HEADERS} ${COMMON_DEPS} ${IMPL_DEPS} lib/libturnclient.a
+
+TURN_BUILD_RESULTS = bin/turnutils_stunclient bin/turnutils_rfc5769check bin/turnutils_uclient bin/turnserver bin/turnutils_peer lib/libturnclient.a include/turn/ns_turn_defs.h
+
+all:	${TURN_BUILD_RESULTS}
+
+test:	check
+
+check:	bin/turnutils_rfc5769check
+	bin/turnutils_rfc5769check
+
+include/turn/ns_turn_defs.h:	src/ns_turn_defs.h
+	${RMCMD} include
+	${MKBUILDDIR} include/turn/client
+	cp -pf src/client/*.h include/turn/client/
+	cp -pf src/client++/*.h include/turn/client/
+	cp -pf src/ns_turn_defs.h include/turn/
+
+bin/turnutils_uclient:	${COMMON_DEPS} src/apps/uclient/session.h lib/libturnclient.a src/apps/uclient/mainuclient.c src/apps/uclient/uclient.c src/apps/uclient/uclient.h src/apps/uclient/startuclient.c src/apps/uclient/startuclient.h
+	${MKBUILDDIR} bin
+	${CC} ${CPPFLAGS} ${CFLAGS} src/apps/uclient/uclient.c src/apps/uclient/startuclient.c src/apps/uclient/mainuclient.c ${COMMON_MODS} -o $@ -Llib -lturnclient -Llib ${LDFLAGS}  
+
+bin/turnutils_stunclient:	${COMMON_DEPS} lib/libturnclient.a src/apps/stunclient/stunclient.c 
+	pwd
+	${MKBUILDDIR} bin
+	${CC} ${CPPFLAGS} ${CFLAGS} src/apps/stunclient/stunclient.c ${COMMON_MODS} -o $@ -Llib -lturnclient -Llib ${LDFLAGS}   
+
+bin/turnutils_rfc5769check:	${COMMON_DEPS} lib/libturnclient.a src/apps/rfc5769/rfc5769check.c 
+	pwd
+	${MKBUILDDIR} bin
+	${CC} ${CPPFLAGS} ${CFLAGS} src/apps/rfc5769/rfc5769check.c ${COMMON_MODS} -o $@ -Llib -lturnclient -Llib ${LDFLAGS} 
+
+bin/turnserver:	${SERVERAPP_DEPS}
+	${MKBUILDDIR} bin
+	${RMCMD} bin/turnadmin
+	${CC} ${CPPFLAGS} ${CFLAGS} ${DBCFLAGS} ${IMPL_MODS} -Ilib ${SERVERAPP_MODS} ${COMMON_MODS} ${SERVERTURN_MODS} -o $@ ${DBLIBS} ${LDFLAGS} 
+	cd bin; ln -s turnserver turnadmin  
+
+bin/turnutils_peer:	${COMMON_DEPS} ${LIBCLIENTTURN_MODS} ${LIBCLIENTTURN_DEPS} lib/libturnclient.a src/apps/peer/mainudpserver.c src/apps/peer/udpserver.h src/apps/peer/udpserver.c
+	${MKBUILDDIR} bin
+	${CC} ${CPPFLAGS} ${CFLAGS} src/apps/peer/mainudpserver.c src/apps/peer/udpserver.c ${COMMON_MODS} -o $@ -Llib -lturnclient -Llib ${LDFLAGS}  
+
+### Client Library:
+
+lib/libturnclient.a:	${LIBCLIENTTURN_OBJS} ${LIBCLIENTTURN_DEPS}
+	${MKBUILDDIR} lib
+	${ARCHIVERCMD} $@ ${LIBCLIENTTURN_OBJS}
+
+build/obj/ns_turn_ioaddr.o:	src/client/ns_turn_ioaddr.c ${LUBCLIENTTURN_DEPS}
+	${MKBUILDDIR} build/obj
+	${CC} ${CPPFLAGS} ${CFLAGS} -c src/client/ns_turn_ioaddr.c -o $@
+
+build/obj/ns_turn_msg_addr.o:	src/client/ns_turn_msg_addr.c ${LUBCLIENTTURN_DEPS}
+	${MKBUILDDIR} build/obj
+	${CC} ${CPPFLAGS} ${CFLAGS} -c src/client/ns_turn_msg_addr.c -o $@
+
+build/obj/ns_turn_msg.o:	src/client/ns_turn_msg.c ${LUBCLIENTTURN_DEPS}
+	${MKBUILDDIR} build/obj
+	${CC} ${CPPFLAGS} ${CFLAGS} -c src/client/ns_turn_msg.c -o $@
+
+### Clean all:
+
+clean:	
+	${RMCMD} bin build lib obj *bak *~ */*~ */*/*~ */*/*/*~ *core */*core */*/*core include Makefile tmp
+
+distclean:	clean
+
+### Install all:
+
+install:	all ${MAKE_DEPS}
+	${MKDIR} ${DESTDIR}${PREFIX}
+	${MKDIR} ${DESTDIR}${BINDIR}
+	${MKDIR} ${DESTDIR}${MANPREFIX}/man/man1
+	${MKDIR} ${DESTDIR}${CONFDIR}
+	${MKDIR} ${DESTDIR}${LIBDIR}
+	${MKDIR} ${DESTDIR}${EXAMPLESDIR}
+	${MKDIR} ${DESTDIR}${DOCSDIR}
+	${MKDIR} ${DESTDIR}${SCHEMADIR}
+	${MKDIR} ${DESTDIR}${TURNINCLUDEDIR}
+	${INSTALL_PROGRAM} bin/turnserver ${DESTDIR}${BINDIR}
+	${INSTALL_PROGRAM} bin/turnadmin ${DESTDIR}${BINDIR}
+	${INSTALL_PROGRAM} bin/turnutils_uclient ${DESTDIR}${BINDIR}
+	${INSTALL_PROGRAM} bin/turnutils_peer ${DESTDIR}${BINDIR}
+	${INSTALL_PROGRAM} bin/turnutils_stunclient ${DESTDIR}${BINDIR}
+	${INSTALL_MAN} man/man1/turnserver.1 ${DESTDIR}${MANPREFIX}/man/man1/
+	${INSTALL_MAN} man/man1/turnadmin.1 ${DESTDIR}${MANPREFIX}/man/man1/
+	${INSTALL_MAN} man/man1/turnutils.1 ${DESTDIR}${MANPREFIX}/man/man1/
+	${INSTALL_MAN} man/man1/turnutils_uclient.1 ${DESTDIR}${MANPREFIX}/man/man1/
+	${INSTALL_MAN} man/man1/turnutils_stunclient.1 ${DESTDIR}${MANPREFIX}/man/man1/
+	${INSTALL_MAN} man/man1/turnutils_peer.1 ${DESTDIR}${MANPREFIX}/man/man1/
+	${INSTALL_MAN} man/man1/coturn.1 ${DESTDIR}${MANPREFIX}/man/man1/
+	${INSTALL_STATIC_LIB} lib/libturnclient.a ${DESTDIR}${LIBDIR}
+	${INSTALL_DATA} LICENSE ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} README.turnserver ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} README.turnadmin ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} README.turnutils ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} INSTALL ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} postinstall.txt ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} turndb/schema.sql ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} turndb/schema.sql ${DESTDIR}${SCHEMADIR}
+	${INSTALL_DATA} turndb/testredisdbsetup.sh ${DESTDIR}${SCHEMADIR}
+	${INSTALL_DATA} turndb/testsqldbsetup.sql ${DESTDIR}${SCHEMADIR}
+	${INSTALL_DATA} turndb/schema.userdb.redis ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} turndb/schema.userdb.redis ${DESTDIR}${SCHEMADIR}
+	${INSTALL_DATA} turndb/schema.stats.redis ${DESTDIR}${DOCSDIR}
+	${INSTALL_DATA} turndb/schema.stats.redis ${DESTDIR}${SCHEMADIR}
+	${INSTALL_DATA} examples/etc/turnserver.conf ${DESTDIR}${CONFDIR}/turnserver.conf.default
+	${INSTALL_DATA} examples/etc/turnuserdb.conf ${DESTDIR}${CONFDIR}/turnuserdb.conf.default
+	${INSTALL_DIR} examples/etc ${DESTDIR}${EXAMPLESDIR}
+	${INSTALL_DIR} examples/scripts ${DESTDIR}${EXAMPLESDIR}
+	${RMCMD} ${DESTDIR}${EXAMPLESDIR}/scripts/rfc5769.sh
+	${INSTALL_DIR} include/turn/client ${DESTDIR}${TURNINCLUDEDIR}
+	${INSTALL_DATA} include/turn/ns_turn_defs.h ${DESTDIR}${TURNINCLUDEDIR}
+	${MORECMD} ${DESTDIR}${DOCSDIR}/postinstall.txt
+
+deinstall:	${MAKE_DEPS}
+	${PKILL_PROGRAM} turnserver || ${ECHO_CMD} OK
+	${RMCMD} ${DESTDIR}${DOCSDIR}
+	${RMCMD} ${DESTDIR}${SCHEMADIR}
+	${RMCMD} ${DESTDIR}${BINDIR}/turnserver
+	${RMCMD} ${DESTDIR}${BINDIR}/turnadmin
+	${RMCMD} ${DESTDIR}${BINDIR}/turnutils_peer
+	${RMCMD} ${DESTDIR}${BINDIR}/turnutils_uclient
+	${RMCMD} ${DESTDIR}${BINDIR}/turnutils_stunclient
+	${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnserver.1
+	${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnadmin.1
+	${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils.1
+	${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils_uclient.1
+	${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils_stunclient.1
+	${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/turnutils_peer.1
+	${RMCMD} ${DESTDIR}${MANPREFIX}/man/man1/coturn.1
+	${RMCMD} ${DESTDIR}${LIBDIR}/libturnclient.a
+	${RMCMD} ${DESTDIR}${EXAMPLESDIR}/
+	${RMCMD} ${DESTDIR}${CONFDIR}/turnserver.conf.default
+	${RMCMD} ${DESTDIR}${CONFDIR}/turnuserdb.conf.default
+	${RMCMD} ${DESTDIR}${TURNINCLUDEDIR}
+
+uninstall:	deinstall
+
+reinstall:	deinstall install
+
+

+ 2 - 0
NOTE

@@ -0,0 +1,2 @@
+This project is active in Google code: http://code.google.com/p/coturn/
+

+ 239 - 0
README.turnadmin

@@ -0,0 +1,239 @@
+GENERAL INFORMATION
+
+turnadmin is a TURN administration tool. This tool can be used to manage 
+the user accounts (add/remove users, generate 
+TURN keys for the users). For security reasons, we do not recommend 
+storing passwords openly. The better option is to use pre-processed "keys" 
+which are then used for authentication. These keys are generated by turnadmin. 
+Turnadmin is a link to turnserver binary, but turnadmin performs different 
+functions.
+
+Options note: turnadmin has long and short option names, for most options.
+Some options have only long form, some options have only short form. Their syntax 
+somewhat different, if an argument is required:
+
+The short form must be used as this (for example):
+
+  $ turnadmin -u <username> ...
+  
+The long form equivalent must use the "=" character:
+
+  $ turnadmin --user=<username> ...
+  
+If this is a flag option (no argument required) then their usage are the same, for example:
+
+ $ turnadmin -k ...
+ 
+is equivalent to:
+
+ $ turnadmin --key ...
+
+You have always the use the -r <realm> option with commands for long term credentials - 
+because data for multiple realms can be stored in the same database.
+ 
+=====================================
+
+  NAME
+
+turnadmin - a TURN relay administration tool. 
+  
+  SYNOPSIS  
+
+$ turnadmin [command] [options]
+
+$ turnadmin [ -h | --help]
+
+  DESCRIPTION
+  
+Commands:  
+
+-k, --key		Generate key for a long-term credentials mechanism user.
+
+-a, --add       	Add or update a long-term user.
+
+-A, --add-st    	Add or update a short-term credentials mechanism user.
+
+-d, --delete		Delete a long-term user.
+
+-D, --delete-st		Delete a short-term user.
+
+-l, --list		List long-term users in the database.
+
+-L, --list-st		List short-term users in the database.
+
+-s, --set-secret=<value> Add shared secret for TURN RESP API
+
+-S, --show-secret	Show stored shared secrets for TURN REST API
+
+-X, --delete-secret=<value> Delete a shared secret.
+	--delete-all_secrets	Delete all shared secrets for REST API.
+	
+-O, --add-origin		Add origin-to-realm relation.
+
+-R, --del-origin		Delete origin-to-realm relation.
+
+-I, --list-origins		List origin-to-realm relations.
+
+-g, --set-realm-option		Set realm params: max-bps, total-quota, user-quota.
+
+-G, --list-realm-options	List realm params.
+
+NOTE: if you are using the flat file for the user database, then you will have 
+to use a text editor to set or show the shared secrets.
+
+NOTE: the origin functionality is not supported with flat user db file, 
+a "real" database must be used.
+  
+Options with required values:  
+
+-b, --userdb		File-based user database file name (default - turnuserdb.conf).
+			See the --userdb option in the turnserver section.
+-e, --psql-userdb	PostgreSQL user database connection string.
+			See the --psql-userdb option in the turnserver section.
+-M, --mysql-userdb	MySQL user database connection string.
+			See the --mysql-userdb option in the turnserver section.
+-N, --redis-userdb	Redis user database connection string.
+			See the --redis-userdb option in the turnserver section.
+-u, --user		User name.
+-r, --realm		Realm, for long-term credentials mechanism only.
+-p, --password		Password.
+-o, --origin		Origin
+-H, --sha256	Use SHA256 as the keys hash function (a non-standard feature). 
+				By default, MD5 is used for the key storage encryption 
+				(as required by the current STUN/TURNstandards).
+--max-bps		Set value of realm's max-bps parameter.
+--total-quota	Set value of realm's total-quota parameter.
+--user-quota	Set value of realm's user-quota parameter. 
+-h, --help		Help.
+  
+Generate a key:  
+
+$ turnadmin -k -u <username> -r <realm> -p <password>
+  
+Add/update a user in the userdb file or in the database:
+
+$ turnadmin -a [-b <userdb-file> | -e <db-connection-string> | -M <db-connection-string> | -N <db-connection-string> ] -u <username> -r <realm> -p <password>
+  
+Delete a user from the userdb file or from the database:
+
+$ turnadmin -d [-b <userdb-file> | -e <db-connection-string> | -M <db-connection-string> | -N <db-connection-string> ] -u <username> -r <realm>
+
+List all long-term users in MySQL database:
+
+$ turnadmin -l --mysql-userdb="<db-connection-string>" -r <realm>
+
+List all short-term users in Redis database:
+
+$ turnadmin -L --redis-userdb="<db-connection-string>"
+
+Set secret in MySQL database:
+
+$ turnadmin -s <secret> --mysql-userdb="<db-connection-string>" -r <realm>
+
+Show secret stored in PostgreSQL database:
+
+$ turnadmin -S --psql-userdb="<db-connection-string>" -r <realm>
+
+Set origin-to-realm relation in MySQL database:
+
+$ turnadmin --mysql-userdb="<db-connection-string>" -r <realm> -o <origin>
+
+Delete origin-to-realm relation from Redis DB:
+
+$ turnadmin --redis-userdb="<db-connection-string>" -o <origin>
+
+List all origin-to-realm relations in Redis DB:
+
+$ turnadmin --redis-userdb="<db-connection-string>" -I
+
+List the origin-to-realm relations in PostgreSQL DB for a single realm:
+
+$ turnadmin --psql-userdb="<db-connection-string>" -I -r <realm>
+  
+Help:  
+
+$ turnadmin -h
+
+=======================================
+ 
+  DOCS
+
+After installation, run the command:
+
+$ man turnadmin
+
+or in the project root directory:
+
+$ man -M man turnadmin
+
+to see the man page.
+
+=====================================
+
+  FILES
+
+/etc/turnserver.conf
+
+/etc/turnuserdb.conf
+
+/usr/local/etc/turnserver.conf
+
+/usr/local/etc/turnuserdb.conf
+
+=====================================
+
+  DIRECTORIES
+
+/usr/local/share/turnserver
+
+/usr/local/share/doc/turnserver
+
+/usr/local/share/examples/turnserver
+
+======================================
+
+  SEE ALSO
+
+	turnserver, turnutils
+
+======================================
+
+  WEB RESOURCES
+
+	project page:
+
+	http://code.google.com/p/coturn/
+
+	Wiki page:
+
+	http://code.google.com/p/coturn/wiki/Readme
+
+	forum:
+
+	https://groups.google.com/forum/?fromgroups=#!forum/turn-server-project-rfc5766-turn-server/
+
+======================================
+
+  AUTHORS
+
+	Oleg Moskalenko <[email protected]>
+
+	Gabor Kovesdan http://kovesdan.org/
+
+	Daniel Pocock http://danielpocock.com/
+
+	John Selbie ([email protected])
+
+	Lee Sylvester <[email protected]>
+
+	Erik Johnston <[email protected]>
+
+	Roman Lisagor <[email protected]>
+	
+	Vladimir Tsanev <[email protected]>
+	
+	Po-sheng Lin <[email protected]>
+	
+	Peter Dunkley <[email protected]>
+	
+	Mutsutoshi Yoshimoto <[email protected]>

+ 880 - 0
README.turnserver

@@ -0,0 +1,880 @@
+GENERAL INFORMATION
+
+The TURN Server project contains the source code of a TURN server and TURN client 
+messaging library. Also, some extra programs provided, for testing-only 
+purposes. 
+
+See the INSTALL file for the building instructions.
+
+After the build, you will have the following binary images:
+
+1.	turnserver: TURN Server relay. 
+The compiled binary image of the TURN Server program is located in bin/ sub-directory.
+
+2.	turnadmin: TURN administration tool. See README.turnadmin and turnadmin man page.
+  
+3.	turnutils_uclient. See README.turnutils and turnutils man page.
+
+4.	turnutils_peer. See README.turnutils and turnutils man page.
+   
+5.	turnutils_stunclient. See README.turnutils and turnutils man page.
+  
+6.	turnutils_rfc5769check. See README.turnutils and turnutils man page.
+
+In the "examples/scripts" sub-directory, you will find the examples of command lines to be used 
+to run the programs. The scripts are meant to be run from examples/ sub-directory, for example:
+
+$ cd examples
+$ ./scripts/secure_relay.sh
+  
+RUNNING THE TURN SERVER
+
+Options note: turnserver has long and short option names, for most options.
+Some options have only long form, some options have only short form. Their syntax 
+somewhat different, if an argument is required:
+
+The short form must be used as this (for example):
+
+  $ turnserver -L 12.34.56.78
+  
+The long form equivalent must use the "=" character:
+
+  $ turnserver --listening-ip=12.34.56.78
+  
+If this is a flag option (no argument required) then their usage are the same, for example:
+
+ $ turnserver -a
+ 
+is equivalent to:
+
+ $ turnserver --lt-cred-mech
+  
+=====================================
+
+  NAME
+  
+turnserver - a TURN relay server implementation.
+  
+  SYNOPSIS
+  
+$ turnserver [-n | -c <config-file> ] [flags] [ --userdb=<userdb-file> | --psql-userdb=<db-conn-string> | --mysql-userdb=<db-conn-string>  | --redis-userdb=<db-conn-string> ] [-z | --no-auth | -a | --lt-cred-mech ] [options]
+$ turnserver -h
+  
+  DESCRIPTION						
+  
+Config file settings:  
+
+-n		Do not use configuration file, use only command line parameters.
+
+-c		Configuration file name (default - turnserver.conf).
+		The format of config file can be seen in
+		the supplied examples/etc/turnserver.conf example file. Long 
+		names of the options are used as the configuration 
+		items names in the file. If not an absolute path is supplied, 
+		then the file is searched in the following directories: 
+		  * current directory
+		  * current directory etc/ sub-directory
+		  * upper directory level etc/
+		  * /etc/ 
+		  * /usr/local/etc/
+		  * installation directory /etc
+
+User database settings:  
+
+-b, --userdb	User database file name (default - turnuserdb.conf),
+		for long-term credentials mechanism only.
+		This user file database is being dynamically checked while the turnserver 
+		is working, and the user accounts can be changed dynamically by
+		editing the database.
+				  
+-e, --psql-userdb	User database connection string for PostgreSQL.
+		This database can be used for long-term and short-term credentials mechanisms,
+		and it can store the secret value for secret-based timed authentication in TURN RESP API.
+		The connection string format is like that:
+		 
+		"host=<host> dbname=<dbname> user=<db-user> password=<db-user-password> connect_timeout=<seconds>" 
+		(for 8.x or newer Postgres).
+		
+		Or:
+		
+		"postgresql://username:password@hostname:port/databasename" (for 9.x or newer Postgres). 
+		See the INSTALL file for more explanations and examples.
+		
+		Also, see http://www.PostgreSQL.org for full PostgreSQL documentation.
+				  
+-M, --mysql-userdb	User database connection string for MySQL or MariaDB. 
+		This database can be used for long-term and short-term credentials mechanisms,
+		and it can store the secret value for secret-based timed authentication in TURN RESP API.
+		The connection string format is like that:
+		 
+		"host=<host> dbname=<dbname> user=<db-user> password=<db-user-password> connect_timeout=<seconds>"
+		See the INSTALL file for more explanations and examples.
+		
+		Also, see http://www.mysql.org or http://mariadb.org 
+		for full MySQL documentation.
+		
+-N, --redis-userdb	User database connection string for Redis. 
+		This database can be used for long-term and short-term credentials mechanisms,
+		and it can store the secret value for secret-based timed authentication in TURN RESP API.
+		The connection string format is like that:
+		 
+		"ip=<ip-addr> dbname=<db-number> password=<db-password> connect_timeout=<seconds>"
+		See the INSTALL file for more explanations and examples.
+		
+		Also, see http://redis.io for full Redis documentation.
+
+Flags:   
+
+-v, --verbose		Moderate verbose mode.
+
+-V, --Verbose		Extra verbose mode, very annoying and not recommended.
+
+-o, --daemon		Run server as daemon.
+
+-f, --fingerprint	Use fingerprints in the TURN messages. If an incoming request
+			contains a fingerprint, then TURN server will always add 
+			fingerprints to the messages in this session, regardless of the
+			per-server setting.
+
+-a, --lt-cred-mech	Use long-term credentials mechanism (this one you need for WebRTC usage). 
+			This option can be used with either flat file user database or 
+			PostgreSQL DB or MySQL DB or Redis for user keys storage.
+-A, --st-cred-mech	Use the short-term credentials mechanism. This option requires
+	                a PostgreSQL or MySQL or Redis DB for short term passwords storage.
+
+-z, --no-auth		Do not use any credentials mechanism, allow anonymous access. 
+			Opposite to -a and -A options. This is default option when no 
+			authentication-related options are set.
+			By default, no credential mechanism is used -
+			any user is allowed.
+
+--use-auth-secret	TURN REST API flag.
+			Flag that sets a special WebRTC authorization option 
+			that is based upon authentication secret. The feature purpose 
+			is to support "TURN Server REST API" as described in
+			the TURN REST API section below.
+			This option uses timestamp as part of combined username:
+			usercombo -> "timestamp:username",
+			turn user -> usercombo,
+			turn password -> base64(hmac(secret key, usercombo)).
+			This allows TURN credentials to be accounted for a specific user id.
+			If you don't have a suitable id, the timestamp alone can be used.
+			This option is just turns on secret-based authentication.
+			The actual value of the secret is defined either by option static-auth-secret,
+			or can be found in the turn_secret table in the database.
+			This option can be used with long-term credentials mechanisms only -
+			it does not make much sense with the short-term mechanism.
+			
+--dh566			Use 566 bits predefined DH TLS key. Default size of the key is 1066.
+
+--dh2066		Use 2066 bits predefined DH TLS key. Default size of the key is 1066.
+
+--no-sslv2		Do not allow SSLv2 protocol.
+
+--no-sslv3		Do not allow SSLv3 protocol.
+
+--no-tlsv1		Do not allow TLSv1 protocol.
+
+--no-tlsv1_1		Do not allow TLSv1.1 protocol.
+
+--no-tlsv1_2		Do not allow TLSv1.2 protocol.
+
+--no-udp		Do not start UDP client listeners.
+
+--no-tcp		Do not start TCP client listeners.
+
+--no-tls		Do not start TLS client listeners.
+
+--no-dtls		Do not start DTLS client listeners.
+
+--no-udp-relay		Do not allow UDP relay endpoints defined in RFC 5766, 
+			use only TCP relay endpoints as defined in RFC 6062.
+
+--no-tcp-relay		Do not allow TCP relay endpoints defined in RFC 6062, 
+			use only UDP relay endpoints as defined in RFC 5766. 
+
+--stale-nonce		Use extra security with nonce value having limited lifetime (600 secs). 
+
+--no-stdout-log		Flag to prevent stdout log messages.
+			By default, all log messages are going to both stdout and to
+			the configured log file. With this option everything will be going to 
+			the log file only (unless the log file itself is stdout).
+			
+--syslog		With this flag, all log will be redirected to the system log (syslog).
+
+--simple-log	This flag means that no log file rollover will be used, and the log file
+				name will be constructed as-is, without PID and date appendage.
+				
+--secure-stun		Require authentication of the STUN Binding request.
+			By default, the clients are allowed anonymous access to the STUN Binding functionality.
+
+-S, --stun-only		Run as STUN server only, all TURN requests will be ignored. 
+			Option to suppress TURN functionality, only STUN requests will be processed.
+
+--no-stun		Run as TURN server only, all STUN requests will be ignored. 
+			Option to suppress STUN functionality, only TURN requests will be processed.
+
+--no-loopback-peers	Disallow peers on the loopback addresses (127.x.x.x and ::1).
+
+--no-multicast-peers	Disallow peers on well-known broadcast addresses 
+			(224.0.0.0 and above, and FFXX:*).
+
+--sha256		Require SHA256 digest function to be used for the message integrity.
+			By default, the server uses SHA1 hashes. With this option, the server 
+			requires the stronger SHA256 hashes. The client application must support
+			SHA256 hash function if this option is used. If the server obtains a message 
+			from the client with a weaker (SHA1) hash function then the server returns 
+			error code 426.
+			
+--mobility		Mobility with ICE (MICE) specs support.
+
+--no-cli		Turn OFF the CLI support. By default it is always ON.
+			See also options --cli-ip and --cli-port.
+				
+--server-relay		Server relay. NON-STANDARD AND DANGEROUS OPTION. 
+			Only for those applications when we want to run 
+			server applications on the relay endpoints.
+			This option eliminates the IP permissions check 
+			on the packets incoming to the relay endpoints.
+			See http://tools.ietf.org/search/rfc5766#section-17.2.3 .
+				
+--udp-self-balance	(recommended for older Linuxes only)
+			Automatically balance UDP traffic over auxiliary servers
+			(if configured). The load balancing is using the 
+			ALTERNATE-SERVER mechanism. The TURN client must support 
+			300 ALTERNATE-SERVER response for this functionality.
+
+-h			Help.
+    
+Options with required values:  
+
+-d, --listening-device	Listener interface device.
+			(NOT RECOMMENDED. Optional functionality, Linux only). 
+			The turnserver process must have root privileges to bind the 
+			listening endpoint to a device. If turnserver must run as a 
+			process without root privileges, then just do not use this setting.
+
+-L, --listening-ip	Listener IP address of relay server. 
+			Multiple listeners can be specified, for example:
+			-L ip1 -L ip2 -L ip3
+			If no IP(s) specified, then all IPv4 and 
+			IPv6 system IPs will be used for listening.
+			The same ip(s) can be used as both listening and relay ip(s).
+
+-p, --listening-port	TURN listener port for UDP and TCP listeners (Default: 3478).
+			Note: actually, TLS & DTLS sessions can connect to the "plain" TCP & UDP
+			port(s), too - if allowed by configuration.
+
+--tls-listening-port	TURN listener port for TLS and DTLS listeners (Default: 5349).
+			Note: actually, "plain" TCP & UDP sessions can connect to the TLS & DTLS
+			port(s), too - if allowed by configuration. The TURN server 
+			"automatically" recognizes the type of traffic. Actually, two listening
+			endpoints (the "plain" one and the "tls" one) are equivalent in terms of
+			functionality; but we keep both endpoints to satisfy the RFC 5766 specs.
+			For secure TCP connections, we currently support SSL version 3 and 
+			TLS versions 1.0, 1.1, 1.2. SSL2 "encapsulation mode" is also supported.
+			For secure UDP connections, we support DTLS version 1.
+
+--alt-listening-port	Alternative listening port for UDP and TCP listeners;
+			default (or zero) value means "listening port plus one".
+			This is needed for STUN CHANGE_REQUEST - in RFC 5780 sense
+                	or in old RFC 3489 sense - for NAT behavior discovery). The TURN Server
+			supports CHANGE_REQUEST only if it is started with more than one
+			listening IP address of the same family (IPv4 or IPv6). The CHANGE_REQUEST
+			is only supported by UDP protocol, other protocols are listening
+			on that endpoint only for "symmetry".
+
+--alt-tls-listening-port	Alternative listening port for TLS and DTLS protocols.
+				Default (or zero) value means "TLS listening port plus one".
+				
+--aux-server		Auxiliary STUN/TURN server listening endpoint.
+			Aux servers have almost full TURN and STUN functionality.
+			The (minor) limitations are:
+				1) Auxiliary servers do not have alternative ports and
+				they do not support STUN RFC 5780 functionality (CHANGE REQUEST).
+				2) Auxiliary servers also are never returning ALTERNATIVE-SERVER reply.
+					
+			Valid formats are 1.2.3.4:5555 for IPv4 and [1:2::3:4]:5555 for IPv6.
+			There may be multiple aux-server options, each will be used for listening
+			to client requests.
+
+-i, --relay-device	Relay interface device for relay sockets 
+			(NOT RECOMMENDED. Optional, Linux only).
+
+-E, --relay-ip		Relay address (the local IP address that 
+			will be used to relay the packets to the 
+			peer). Multiple relay addresses may be used:
+			-E ip1 -E ip2 -E ip3
+			The same IP(s) can be used as both listening IP(s) and relay IP(s).
+			If no relay IP(s) specified, then the turnserver will apply the 
+			default policy: it will decide itself which relay addresses to be 
+			used, and it will always be using the client socket IP address as 
+			the relay IP address of the TURN session (if the requested relay 
+			address family is the same as the family of the client socket).
+
+-X, --external-ip	TURN Server public/private address mapping, if the server is behind NAT.
+			In that situation, if a -X is used in form "-X <ip>" then that ip will be reported
+			as relay IP address of all allocations. This scenario works only in a simple case
+			when one single relay address is be used, and no CHANGE_REQUEST functionality is 
+			required. That single relay address must be mapped by NAT to the 'external' IP.
+			The "external-ip" value, if not empty, is returned in XOR-RELAYED-ADDRESS field.
+			For that 'external' IP, NAT must forward ports directly (relayed port 12345
+			must be always mapped to the same 'external' port 12345).
+			In more complex case when more than one IP address is involved,
+			that option must be used several times, each entry must
+			have form "-X <public-ip/private-ip>", to map all involved addresses.
+			CHANGE_REQUEST (RFC5780 or RFC3489) NAT discovery STUN functionality will work 
+			correctly, if the addresses are mapped properly, even when the TURN server itself 
+			is behind A NAT.
+			By default, this value is empty, and no address mapping is used.
+				
+-m, --relay-threads	Number of relay threads to handle the established connections
+			(in addition to authentication thread and the listener thread).
+			If set to 0 then application runs relay process in a single thread,
+			in the same thread with the listener process (the authentication thread will 
+			still be a separate thread). In older systems (before Linux kernel 3.9),
+			the number of UDP threads is always one threads per network listening endpoint -
+			unless "-m 0" or "-m 1" is set.
+
+--min-port		Lower bound of the UDP port range for relay 
+			endpoints allocation.
+			Default value is 49152, according to RFC 5766.
+
+--max-port		Upper bound of the UDP port range for relay 
+			endpoints allocation.
+			Default value is 65535, according to RFC 5766.
+
+-u, --user		Long-term security mechanism credentials user account, 
+			in the column-separated form username:key. 
+			Multiple user accounts may used in the command line.
+			The key is either the user password, or
+			the key is generated
+			by turnadmin command. In the second case,
+			the key must be prepended with 0x symbols.
+			The key is calculated over the user name, 
+			the user realm, and the user password.
+			This setting may not be used with TURN REST API or
+			with short-term credentials mechanism.
+
+-r, --realm		The default realm to be used for the users when no explicit 
+			origin/realm relationship was found in the database, or if the TURN
+			server is not using any database (just the commands-line settings
+			and the userdb file). Must be used with long-term credentials 
+			mechanism or with TURN REST API.
+
+-C, --rest-api-separator	This is the timestamp/username separator symbol (character) in TURN REST API.
+				The default value is :.
+
+-q, --user-quota	Per-user allocations quota: how many concurrent 
+			allocations a user can create. This option can also be set 
+			through the database, for a particular realm.
+
+-Q, --total-quota	Total allocations quota: global limit on concurrent allocations.
+			This option can also be set through the database, for a particular realm.
+
+-s, --max-bps		Max bytes-per-second bandwidth a TURN session is allowed to handle
+			(input and output network streams are treated separately). Anything above 
+			that limit will be dropped or temporary suppressed (within the
+			available buffer limits). This option can also be set through the 
+			database, for a particular realm.
+
+--static-auth-secret	Static authentication secret value (a string) for TURN REST API only.
+			If not set, then the turn server will try to use the dynamic value 
+			in turn_secret table in user database (if present). The database-stored
+			value can be changed on-the-fly by a separate program, so this is why
+			that other mode is dynamic. Multiple shared secrets can be used
+			(both in the database and in the "static" fashion).
+
+--cert			Certificate file, PEM format. Same file 
+			search rules applied as for the configuration 
+			file. If both --no-tls and --no-dtls options 
+			are specified, then this parameter is not needed.
+			Default value is turn_server_cert.pem.
+
+--pkey		     	Private key file, PEM format. Same file 
+			search rules applied as for the configuration 
+			file. If both --no-tls and --no-dtls options 
+			are specified, then this parameter is not needed.
+			Default value is turn_server_pkey.pem.
+			
+--pkey-pwd		If the private key file is encrypted, then this password to be used.
+
+--cipher-list		Allowed OpenSSL cipher list for TLS/DTLS connections.
+			Default value is "DEFAULT".
+				
+--CA-file		CA file in OpenSSL format. 
+			Forces TURN server to verify the client SSL certificates.
+			By default, no CA is set and no client certificate check is performed.
+
+--ec-curve-name		Curve name for EC ciphers, if supported by OpenSSL library (TLS and DTLS).
+			The default value is prime256v1.
+
+--dh-file		Use custom DH TLS key, stored in PEM format in the file.
+			Flags --dh566 and --dh2066 are ignored when the DH key is taken from a file.
+
+-l, --log-file		Option to set the full path name of the log file.
+			By default, the turnserver tries to open a log file in 
+			/var/log/turnserver, /var/log, /var/tmp, /tmp and . (current) 
+			directories (which file open operation succeeds 
+			first that file will be used). With this option you can set the 
+			definite log file name.
+			The special names are "stdout" and "-" - they will force everything 
+			to the stdout. Also, "syslog" name will redirect everything into
+			the system log (syslog), as if the option "--syslog" was set.
+				
+--alternate-server	Option to set the "redirection" mode. The value of this option
+			will be the address of the alternate server for UDP & TCP service in form of 
+			<ip>[:<port>]. The server will send this value in the attribute
+			ALTERNATE-SERVER, with error 300, on ALLOCATE request, to the client.
+			Client will receive only values with the same address family
+			as the client network endpoint address family. 
+			See RFC 5389 and RFC 5766 for ALTERNATE-SERVER functionality description. 
+			The client must use the obtained value for subsequent TURN communications.
+			If more than one --alternate-server options are provided, then the functionality
+			can be more accurately described as "load-balancing" than a mere "redirection". 
+			If the port number is omitted, then the default port 
+			number 3478 for the UDP/TCP protocols will be used.
+			Colon (:) characters in IPv6 addresses may conflict with the syntax of 
+			the option. To alleviate this conflict, literal IPv6 addresses are enclosed 
+			in square brackets in such resource identifiers, for example: 
+			[2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478 . 
+			Multiple alternate servers can be set. They will be used in the
+			round-robin manner. All servers in the pool are considered of equal weight and 
+			the load will be distributed equally. For example, if we have 4 alternate servers, 
+			then each server will receive 25% of ALLOCATE requests. An alternate TURN server 
+			address can be used more than one time with the alternate-server option, so this 
+			can emulate "weighting" of the servers. 
+
+--tls-alternate-server	Option to set alternative server for TLS & DTLS services in form of 
+			<ip>:<port>. If the port number is omitted, then the default port 
+			number 5349 for the TLS/DTLS protocols will be used. See the previous option for the 
+			functionality description.
+
+-O, --redis-statsdb	Redis status and statistics database connection string, if used (default - empty, 
+			no Redis stats DB used). This database keeps allocations status information, and it can 
+			be also used for publishing and delivering traffic and allocation event notifications.
+			This database option can be used independently of --redis-userdb option,
+			and actually Redis can be used for status/statistics and MySQL or PostgreSQL can
+			be used for the user database.
+			The connection string has the same parameters as redis-userdb connection string.
+
+--max-allocate-timeout	Max time, in seconds, allowed for full allocation establishment. 
+			Default is 60 seconds.
+
+--denied-peer-ip=<IPaddr[-IPaddr]>
+
+--allowed-peer-ip=<IPaddr[-IPaddr]> Options to ban or allow specific ip addresses or ranges 
+			of ip addresses. If an ip address is specified as both allowed and denied, then 
+			the ip address is considered to be allowed. This is useful when you wish to ban
+			a range of ip addresses, except for a few specific ips within that range.
+			This can be used when you do not want users of the turn server to be able to access
+			machines reachable by the turn server, but would otherwise be unreachable from the 
+			internet (e.g. when the turn server is sitting behind a NAT). The 'white" and "black" peer 
+			IP ranges can also be dynamically changed in the database. 
+			The allowed/denied addresses (white/black lists) rules are very simple:
+			1) If there is no rule for an address, then it is allowed; 
+			2) If there is an "allowed" rule that fits the address then it is allowed - no matter what;
+			3) If there is no "allowed" rule that fits the address, and if there is a "denied" rule that
+			fits the address, then it is denied.
+
+--pidfile 		File name to store the pid of the process.
+			Default is /var/run/turnserver.pid (if superuser account is used) or
+			/var/tmp/turnserver.pid .
+				
+--proc-user		User name to run the process. After the initialization, the turnserver process
+			will make an attempt to change the current user ID to that user.
+	
+--proc-group		Group name to run the process. After the initialization, the turnserver process
+			will make an attempt to change the current group ID to that group.
+			
+--cli-ip		Local system IP address to be used for CLI management interface.
+			The turnserver process can be accessed for management with telnet,
+			at this IP address and on the CLI port (see the next parameter). 
+			Default value is 127.0.0.1. You can use telnet or putty (in telnet mode)
+			to access the CLI management interface. 
+					
+--cli-port		CLI management interface listening port. Default is 5766.
+
+--cli-password		CLI access password. Default is empty (no password).
+
+--cli-max-output-sessions	Maximum number of output sessions in ps CLI command.
+			This value can be changed on-the-fly in CLI. The default value is 256.
+
+--ne=[1|2|3]			Set network engine type for the process (for internal purposes).
+
+==================================
+
+LOAD BALANCE AND PERFORMANCE TUNING
+
+This topic is covered in the wiki page:
+
+http://code.google.com/p/coturn/wiki/turn_performance_and_load_balance
+	 
+===================================
+
+WEBRTC USAGE
+
+This is a set of notes for the WebRTC users:
+
+1) WebRTC uses long-term authentication mechanism, so you have to use -a 
+option (or --lt-cred-mech). WebRTC relaying will not work with anonymous access 
+or with short-term authentication. With -a option, do not forget to set the 
+default realm (-r option). You will also have to set up the user accounts, 
+for that you have a number of options:
+
+	a) command-line options (-u).
+	
+	b) userdb config file.
+	
+	c) a database table (PostgreSQL or MySQL). You will have to set keys with 
+	turnadmin utility (see docs and wiki for turnadmin). You cannot use open passwords 
+	in the database.
+
+	d) Redis key/value pair(s), if Redis is used. You key use either keys or 
+	open passwords with Redis; see turndb/testredisdbsetup.sh file.  
+	
+	e) You also can use the TURN REST API. You will need shared secret(s) set
+	either	through the command line option, or through the config file, or through
+	the database table or Redis key/value pairs.  
+
+2) Usually WebRTC uses fingerprinting (-f).
+
+3) -v option may be nice to see the connected clients.
+
+4) -X is needed if you are running your TURN server behind a NAT.
+
+5) --min-port and --max-port may be needed if you want to limit the relay endpoints ports 
+number range.
+
+===================================
+
+TURN REST API
+
+In WebRTC, the browser obtains the TURN connection information from the web
+server. This information is a secure information - because it contains the 
+necessary TURN credentials. As these credentials are transmitted over the 
+public networks, we have a potential security breach.
+
+If we have to transmit a valuable information over the public network, 
+then this information has to have a limited lifetime. Then the guy who 
+obtains this information without permission will be able to perform 
+only limited damage.
+
+This is how the idea of TURN REST API - time-limited TURN credentials - 
+appeared. This security mechanism is based upon the long-term credentials 
+mechanism. The main idea of the REST API is that the web server provides 
+the credentials to the client, but those credentials can be used only 
+limited time by an application that has to create a TURN server connection.
+
+The "classic" long-term credentials mechanism (LTCM) is described here:
+
+http://tools.ietf.org/html/rfc5389#section-10.2
+http://tools.ietf.org/html/rfc5389#section-15.4
+
+For authentication, each user must know two things: the username and the 
+password. Optionally, the user must supply the ORIGIN value, so that the 
+server can figure out the realm to be used for the user. The nonce and 
+the realm values are supplied by the TURN server. But LTCM is not saying 
+anything about the nature and about the persistence 
+of the username and of the password; and this is used by the REST API.
+
+In the TURN REST API, there is no persistent passwords for users. A user has 
+just the username. The password is always temporary, and it is generated by 
+the web server on-demand, when the user accesses the WebRTC page. And, 
+actually, a temporary one-time session only, username is provided to the user, 
+too. 
+
+The temporary user is generated as:
+
+temporary-username="timestamp" + ":" + "username"
+
+where username is the persistent user name, and the timestamp format is just 
+seconds sinse 1970 - the same value as time(NULL) function returns.
+
+The temporary password is obtained as HMAC-SHA1 function over the temporary
+username, with shared secret as the HMAC key, and then the result is encoded:
+
+temporary-password = base64_encode(hmac-sha1(shared-secret, temporary-username))
+
+Both the TURN server and the web server know the same shared secret. How the
+shared secret is distributed among the involved entities is left to the WebRTC
+deployment details - this is beyond the scope of the TURN REST API.
+
+So, a timestamp is used for the temporary password calculation, and this 
+timestamp can be retrieved from the temporary username. This information
+is valuable, but only temporary, while the timestamp is not expired. Without
+knowledge of the shared secret, a new temporary password cannot be generated.
+
+This is all formally described in Justin's Uberti TURN REST API document
+that can be obtained following the link "TURN REST API" in the TURN Server
+project's page http://code.google.com/p/coturn/.
+
+Once the temporary username and password are obtained by the client (browser)
+application, then the rest is just 'classic" long-term credentials mechanism.
+For developers, we are going to describe it step-by-step below:
+
+  - a new TURN client sends a request command to the TURN server.
+  - TURN server sees that this is a new client and the message is not 
+  	authenticated.
+  - the TURN server generates a random nonce string, and return the 
+  	error 401 to the client, with nonce and realm included.
+  - the client sees the 401 error and it extracts two values from 
+  	the error response: the nonce and the realm.
+  - the client uses username, realm and password to produce a key:
+
+         key = MD5(username ":" realm ":" SASLprep(password))
+ (SASLprep is described here: http://tools.ietf.org/html/rfc4013)
+ 
+  - the client forms a new request, adds username, realm and nonce to the 
+  	request. Then, the client calculates and adds the integrity field to 
+  	the request. This is the trickiest part of the process, and it is
+  	 described in the end of section 15.4: 
+  	http://tools.ietf.org/html/rfc5389#section-15.4
+  - the client, optionally, adds the fingerprint field. This may be also 
+  	a tricky procedure, described in section 15.5 of the same document. 
+  	WebRTC usually uses fingerprinted TURN messages.
+  - the TURN server receives the request, reads the username.
+  - then the TURN server checks that the nonce and the realm in the request 
+  	are the valid ones.
+  - then the TURN server calculates the key.
+  - then the TURN server calculates the integrity field.
+  - then the TURN server compares the calculated integrity field with the 
+  	received one - they must be the same. If the integrity fields differ, 
+  	then the request is rejected.
+
+In subsequent communications, the client may go with exactly the same 
+sequence, but for optimization usually the client, having already 
+information about realm and nonce, pre-calculates the integrity string 
+for each request, so that the 401 error response becomes unnecessary. 
+The TURN server may use "--stale-nonce" option for extra security: in 
+some time, the nonce expires and the client will obtain 438 error response
+with the new nonce, and the client will have to start using the new nonce.
+
+In subsequent communications, the sever and the client will always assume 
+the same password - the original password becomes the session parameter and 
+is never expiring. So the password is not changing while the session is valid
+and unexpired. So, if the session is properly maintained, it may go forever, 
+even if the user password has been already changed (in the database). The 
+session simply is using the old password. Once the session got disconnected, 
+the client will have to use the new password to re-connect (if the password 
+has been changed).
+
+An example when a new shared secret is generated every hour by the TURN server
+box and then supplied to the web server, remotely, is provided in the script
+examples/scripts/restapi/shared_secret_maintainer.pl .
+
+A very important thing is that the nonce must be totally random and it must be 
+different for different clients and different sessions. 
+	 
+===================================
+
+DATABASES
+
+For the user database, the turnserver has the following options:
+
+1) Users can be set in the command line, with multiple -u or --user options. 
+Obviously, only a few users can be set that way, and their credentials are fixed 
+for the turnserver process lifetime.
+
+2) Users can be set in turnusers.conf flat file DB. The turnserver process periodically 
+re-reads this file, so the user accounts may be changed while the turnserver is running.
+But still a relatively small (up to a hundred ?) number of users can be handled that way.
+
+3) Users can be stored in PostgreSQL database, if the turnserver was compiled with PostgreSQL
+support. Each time turnserver checks user credentials, it reads the database (asynchronously,
+of course, so that the current flow of packets is not delayed in any way), so any change in the 
+database content is immediately visible by the turnserver. This is the way if you need the 
+best scalability. The schema for the database can be found in schema.sql file.
+For long-term credentials, you have to set the "keys" for the users; the "keys" are generated 
+by the turnadmin utility. For the key generation, you need username, password and the realm. 
+All users in the database must use the same realm value; if down the road you will decide 
+to change the realm name, then you will have to re-generate all user keys (that can be done 
+in a batch script). If you are using short-term credentials, then you use open passwords 
+in the database; you will have to make sure that nobody can access the database outside of 
+the TURN server box. See the file turndb/testsqldbsetup.sql as an example.
+
+4) The same is true for MySQL database. The same schema file is applicable. 
+The same considerations are applicable. 
+
+5) The same is true for the Redis database, but the Redis database has aa different schema -
+it can be found (in the form of explanation) in schema.userdb.redis. 
+Also, in Redis you can store both "keys" and open passwords (for long term credentials) - 
+the "open password" option is less secure but more convenient for low-security environments. 
+For short-term credentials, you will use open passwords only. See the file 
+turndb/testredisdbsetup.sh as an example. 
+
+6) Of course, the turnserver can be used in non-secure mode, when users are allowed to establish
+sessions anonymously. But in most cases (like WebRTC) that will not work.
+
+For the status and statistics database, there are two choices:
+
+1) The simplest choice is not to use it. Do not set --redis-statsdb option, and this functionality 
+will be simply ignored.
+
+2) If you choose to use it, then set the --redis-statsdb option. This may be the same database
+as in --redis-userdb option, or it may be a different database. You may want to use different 
+database for security or convenience reasons. Also, you can use different database management
+systems for the user database and for the ststus and statistics database. For example, you can use 
+MySQL as the user database, and you can use redis for the statistics. Or you can use Redis for both.
+
+So, we have 6 choices for the user management, and 2 choices for the statistics management. These
+two are totally independent. So, you have overall 6*2=12 ways to handle persistent information, 
+choose any for your convenience.
+
+You do not have to handle the database information "manually" - the turnadmin program can handle 
+everything for you. For PostgreSQL and MySQL you will just have to create an empty database
+with schema.sql SQL script. With Redis, you do not have to do even that - just run turnadmin and 
+it will set the users for you (see the turnadmin manuals).
+    
+=================================
+
+LIBRARIES
+
+In the lib/ sub-directory the build process will create TURN client messaging library.
+In the include/ sub-directory, the necessary include files will be placed.
+The C++ wrapper for the messaging functionality is located in TurnMsgLib.h header.
+An example of C++ code can be found in stunclient.c file. 
+
+=================================
+ 
+DOCS
+
+After installation, run the command:
+
+$ man turnserver
+
+or in the project root directory:
+
+$ man -M man turnserver
+
+to see the man page.
+
+In the docs/html subdirectory of the original archive tree, you will find the client library 
+reference. After the installation, it will be placed in PREFIX/share/doc/turnserver/html.
+
+=================================
+
+LOGS
+
+When the TURN Server starts, it makes efforts to create a log file turn_<pid>.log 
+in the following directories:
+
+	* /var/log
+	* /log/
+	* /var/tmp
+	* /tmp
+	* current directory
+
+If all efforts failed (due to the system permission settings) then all 
+log messages are sent only to the standard output of the process.
+
+This behavior can be controlled by --log-file, --syslog and --no-stdout-log options.
+
+=================================
+
+TELNET CLI
+
+The turnserver process provides a telnet CLI access as statistics and basic management
+interface. By default, the turnserver starts a telnet CLI listener on IP 127.0.0.1 and
+port 5766. That can be changed by the command-cline options of the turnserver process
+(see --cli-ip and --cli-port options). The full list of telnet CLI commands is provided
+in "help" command output in the telnet CLI.
+
+=================================
+
+CLUSTERS
+
+TURN Server can be a part of the cluster installation. But, to support the "even port" functionality 
+(RTP/RTCP streams pairs) the client requests from a particular IP must be delivered to the same 
+TURN Server instance, so it requires some networking setup massaging for the cluster. The reason is that 
+the RTP and RTCP relaying endpoints must be allocated on the same relay IP. It would be possible 
+to design a scheme with the application-level requests forwarding (and we may do that later) but 
+it would affect the performance.
+
+=================================
+
+FILES
+
+/etc/turnserver.conf
+
+/etc/turnuserdb.conf
+
+/usr/local/etc/turnserver.conf
+
+/usr/local/etc/turnuserdb.conf
+
+=================================
+
+DIRECTORIES
+
+/usr/local/share/turnserver
+
+/usr/local/share/doc/turnserver
+
+/usr/local/share/examples/turnserver
+
+=================================
+
+STANDARDS
+
+obsolete STUN RFC 3489
+
+new STUN RFC 5389
+
+TURN RFC 5766
+
+TURN-TCP extension RFC 6062
+ 
+TURN IPv6 extension RFC 6156
+
+STUN/TURN test vectors RFC 5769
+
+STUN NAT behavior discovery RFC 5780
+
+=================================
+
+SEE ALSO
+
+	turnadmin, turnutils
+
+======================================
+
+  WEB RESOURCES
+
+	project page:
+
+	http://code.google.com/p/coturn/
+
+	Wiki page:
+
+	http://code.google.com/p/coturn/wiki/Readme
+
+	forum:
+
+	https://groups.google.com/forum/?fromgroups=#!forum/turn-server-project-rfc5766-turn-server/
+
+======================================
+
+  AUTHORS
+
+	Oleg Moskalenko <[email protected]>
+
+	Gabor Kovesdan http://kovesdan.org/
+
+	Daniel Pocock http://danielpocock.com/
+
+	John Selbie ([email protected])
+
+	Lee Sylvester <[email protected]>
+
+	Erik Johnston <[email protected]>
+
+	Roman Lisagor <[email protected]>
+	
+	Vladimir Tsanev <[email protected]>
+	
+	Po-sheng Lin <[email protected]>
+	
+	Peter Dunkley <[email protected]>
+	
+	Mutsutoshi Yoshimoto <[email protected]>

+ 329 - 0
README.turnutils

@@ -0,0 +1,329 @@
+GENERAL INFORMATION
+
+A set of turnutils_* programs provides some utility functionality to be used
+for testing and for setting up the TURN server. 
+  
+1.	turnutils_uclient: emulates multiple UDP,TCP,TLS or DTLS clients. 
+(this program is provided for the testing purposes only !)
+The compiled binary image of this program is located in bin/ 
+sub-directory.
+
+WARNING: the turnutils_uclient program is a primitive client application. 
+It does not implement the re-transmission pattern that is necessary for 
+a correct TURN client implementation. In TURN, the retransmission burden 
+is lying almost entirely on the client application. We provide the messaging 
+functionality in the client library, but the client must implement 
+the correct Networking IO processing in the client program code.
+
+2.	turnutils_peer: a simple stateless UDP-only "echo" server, 
+to be used as the final server in relay pattern ("peer"). For every incoming 
+UDP packet, it simply echoes it back.
+(this program is provided for the testing purposes only !) 
+When the test clients are communicating in the client-to-client manner 
+(when the "turnutils_uclient" program is used with "-y" option) then the 
+turnutils_peer is not needed.
+	
+The compiled binary image of this program is located in bin/ subdirectory.
+   
+3.	turnutils_stunclient: a simple STUN client example. 
+The compiled binary image of this program is located in bin/ subdirectory.
+  
+4.	turnutils_rfc5769check: a utility that checks the correctness of the 
+STUN/TURN protocol implementation. This utility is used only for the compilation
+check procedure, it is not copied to the installation destination.
+
+
+In the "examples/scripts" subdirectory, you will find the examples of command lines to be used 
+to run the programs. The scripts are meant to be run from examples/ subdirectory, for example:
+
+$ cd examples
+
+$ ./scripts/secure_relay.sh
+
+=====================================
+    
+  NAME
+  
+turnutils_uclient - this client emulation application is supplied for the test purposes only.
+ 
+  SYNOPSIS  
+
+$ turnutils_uclient [-tTSvsyhcxg] [options] <TURN-Server-IP-address>
+  
+  DESCRIPTION
+  
+It was designed to simulate multiple clients. It uses asynch IO API in 
+libevent to handle multiple clients. A client connects to the relay, 
+negotiates the session, and sends multiple (configured number) messages to the server (relay), 
+expecting the same number of replies. The length of the messages is configurable. 
+The message is an arbitrary octet stream, but it can be configured as a string. 
+The number of the messages to send is configurable.
+
+Flags:   
+
+-t      Use TCP for communications between client and TURN server (default is UDP).
+
+-T      Use TCP for the relay transport (default - UDP). Implies options -t, -y, -c, 
+    	and ignores flags and options -s, -e, -r and -g.
+    	
+-P      Passive TCP (RFC6062 with active peer). Implies -T.
+
+-S      Secure SSL connection: SSL/TLS for TCP, DTLS for UDP.
+
+-U      Secure unencrypted connection (suite eNULL): SSL/TLS for TCP, DTLS for UDP.
+
+-v      Verbose.
+
+-s      Use "Send" method in TURN; by default, it uses TURN Channels.
+
+-y      Use client-to-client connections: 
+    	RTP/RTCP pair of channels to another RTP/RTCP pair of channels.
+    	with this option the turnutils_peer application is not used,
+    	as the allocated relay endpoints are talking to each other.
+    	 
+-h      Hang on indefinitely after the last sent packet.
+
+-c      Do not create rtcp connections.
+
+-x      Request IPv6 relay address (RFC6156).
+
+-X	IPv4 relay address explicitly requested.
+
+-g      Set DONT_FRAGMENT parameter in TURN requests.
+
+-A	use short-term credentials mechanism for authentication. 
+	By default, the program uses the long-term credentials mechanism 
+	if authentication is required.
+
+-D	Do mandatory channel padding even for UDP (like pjnath).
+
+-N	do negative tests (some limited cases only).
+
+-R	do negative protocol tests.
+
+-O	DOS attack mode.
+
+-H	SHA256 digest function for message integrity calculation.
+	Without this option, by default, SHA1 is used.
+		
+-M	Use TURN ICE Mobility.
+
+-I	Do not set permissions on TURN relay endpoints
+	(for testing the non-standard server relay functionality).
+		
+-G	Generate extra requests (create permissions, channel bind).
+
+Options with required values:  
+
+-l      Message length (Default: 100 Bytes).
+
+-i      Certificate file (for secure connections only, optional).
+
+-k      Private key file (for secure connections only).
+
+-E	CA file for server certificate verification,
+	if the server certificate to be verified.
+
+-p      TURN Server port (Defaults: 3478 unsecure, 5349 secure).
+
+-n      Number of messages to send (Default: 5).
+
+-d      Local interface device (optional, Linux only).
+
+-L      Local IP address (optional).
+
+-m      Number of clients (Default: 1, 2 or 4, depending on options).
+
+-e      Peer address.
+
+-r      Peer port (Default: 3480).
+
+-z      Per-session packet interval in milliseconds (Default: 20).
+
+-u      STUN/TURN user name.
+
+-w      STUN/TURN user password.
+
+-W      TURN REST API authentication secret. Is not compatible with -A flag.
+
+-C	This is the timestamp/username separator symbol (character) in 
+	TURN REST API. The default value is :.
+
+-F	Cipher suite for TLS/DTLS. Default value is DEFAULT.
+
+See the examples in the "examples/scripts" directory.
+
+======================================
+  
+  NAME
+    
+turnutils_peer - a simple UDP-only echo backend server.  
+  
+  SYNOPSYS
+
+$ turnutils_peer [-v] [options]
+  
+  DESCRIPTION
+  
+This application is used for the test purposes only, as a peer for the turnutils_uclient application.
+
+Options with required values:  
+
+-p  Listening UDP port (Default: 3480).
+ 
+-d  Listening interface device (optional)
+
+-L  Listening address of turnutils_peer server. Multiple listening addresses can be used, IPv4 and IPv6.
+If no listener address(es) defined, then it listens on all IPv4 and IPv6 addresses.
+
+-v  Verbose
+
+========================================
+
+  NAME
+  
+turnutils_stunclient -  a basic STUN client. 
+  
+  SYNOPSIS
+
+$ turnutils_stunclient [options] <STUN-Server-IP-address>
+  
+  DESCRIPTION
+  
+It sends a "new" STUN RFC 5389 request (over UDP) and shows the reply information.
+
+Options with required values:  
+
+-p  STUN server port (Default: 3478).
+ 
+-L  Local address to use (optional).
+
+-f  Force RFC 5780 processing.
+
+The turnutils_stunclient program checks the results of the first request, 
+and if it finds that the STUN server supports RFC 5780 
+(the binding response reveals that) then the turnutils_stunclient makes a couple more 
+requests with different parameters, to demonstrate the NAT discovery capabilities.
+
+This utility does not support the "old" "classic" STUN protocol (RFC 3489).
+  
+=====================================
+
+  NAME
+  
+turnutils_rfc5769check - a utility that tests the correctness of STUN protocol implementation.   
+  
+  SYNOPSIS
+  
+  $ turnutils_rfc5769check
+  
+  DESCRIPTION
+
+turnutils_rfc5769check tests the correctness of STUN protocol implementation 
+against the test vectors predefined in RFC 5769 and prints the results of the 
+tests on the screen. This utility is used only for the compilation
+check procedure, it is not copied to the installation destination.
+	
+Usage:  
+
+$ turnutils_rfc5769check
+
+===================================
+ 
+DOCS
+
+After installation, run the command:
+
+$ man turnutils
+
+or in the project root directory:
+
+$ man -M man turnutils
+
+to see the man page.
+
+=====================================
+
+FILES
+
+/etc/turnserver.conf
+
+/etc/turnuserdb.conf
+
+/usr/local/etc/turnserver.conf
+
+/usr/local/etc/turnuserdb.conf
+
+=================================
+
+DIRECTORIES
+
+/usr/local/share/turnserver
+
+/usr/local/share/doc/turnserver
+
+/usr/local/share/examples/turnserver
+
+===================================
+
+STANDARDS
+
+new STUN RFC 5389
+
+TURN RFC 5766
+
+TURN-TCP extension RFC 6062
+ 
+TURN IPv6 extension RFC 6156
+
+STUN/TURN test vectors RFC 5769
+
+STUN NAT behavior discovery RFC 5780
+
+====================================
+
+SEE ALSO
+
+	turnserver, turnadmin
+
+======================================
+
+  WEB RESOURCES
+
+	project page:
+
+	http://code.google.com/p/coturn/
+
+	Wiki page:
+
+	http://code.google.com/p/coturn/wiki/Readme
+
+	forum:
+
+	https://groups.google.com/forum/?fromgroups=#!forum/turn-server-project-rfc5766-turn-server/
+
+======================================
+
+  AUTHORS
+
+	Oleg Moskalenko <[email protected]>
+
+	Gabor Kovesdan http://kovesdan.org/
+
+	Daniel Pocock http://danielpocock.com/
+
+	John Selbie ([email protected])
+
+	Lee Sylvester <[email protected]>
+
+	Erik Johnston <[email protected]>
+
+	Roman Lisagor <[email protected]>
+	
+	Vladimir Tsanev <[email protected]>
+	
+	Po-sheng Lin <[email protected]>
+	
+	Peter Dunkley <[email protected]>
+	
+	Mutsutoshi Yoshimoto <[email protected]>

+ 101 - 0
STATUS

@@ -0,0 +1,101 @@
+Currently implemented functionality:
+
+1) RFC5389 (new STUN protocol) full server and client 
+implementations. We do not maintain strict compatibility 
+with the obsolete RFC 3489 "old STUN" protocol.
+
+2) RFC5766 TURN protocol full server and client 
+implementations. We support file-based long term 
+user credentials, for now. We added experimental DTLS 
+protocol, too. 
+
+3) RFC6156 TURN IPv6 extension.
+
+4) We support the following client-to-server 
+network transports for TURN messages:
+	a) UDP
+	b) TCP
+	c) TLS
+	d) DTLS
+	
+5) Performance tested.
+
+6) Torture and stability tests.
+
+7) Multiple *NIX platforms tested and supported.
+
+8) TTL field handling implemented for all platforms, preferred behavior in RFC5766. 
+
+9) TOS (DiffServ and ECN) field handling (preferred behavior of RFC 5766) implemented,
+for Linux. Other platforms support the alternative behavior of RFC 5766.
+
+10) DF field alternative behavior of RFC 5766 implemented.
+
+11) Bandwidth limitation per session implemented.
+
+12) RFC 5769 test vectors implemented (where applicable).
+
+13) RFC 5780 STUN extension: NAT behavior discovery.
+
+14) C++ mapping implemented.
+
+15) RFC 6062 TCP relaying implemented.
+
+16) Users can be stored in PostgreSQL database.
+
+17) Users can be stored in MySQL database.
+
+18) TURN Server REST API implemented.
+
+19) Short-term credentials mechanism implemented.
+
+20) Simple load-balancing with ALTERNATE-SERVER implemented. 
+
+21) Redis database support added.
+
+22) RFC3489 backward compatibility.
+
+23) Multithreaded TCP relay processing (UDP relay has been 
+multithreaded from the beginning).
+
+24) Networking engine 2.0 implemented, with more scalable approach 
+to the UDP sockets handling.
+
+25) DOS attack prevention logic added to the server; DOS attack client
+emulation implemented. 
+
+26) Linux UDP sockets workaround added to counter RFC 1122 behavior.
+
+27) DTLS sockets re-implemented for better scalability and for Cygwin 
+compatibility.
+
+28) A number of TLS/DTLS improvements added: multiple protocols support, certificate check option.
+
+29) SHA256 support added (experimental).
+
+30) UDP network engine optimized for the new Linux kernels (3.9+).
+
+31) ICE Mobility draft implemented (experimental). 
+
+32) CLI implemented.
+
+33) DH and EC TLS ciphers added.
+
+34) HTTP "keep alive" request supported.
+
+35) Optimized (for thousands and more sessions) timers implementation.
+
+36) TCP network engine optimized for the new Linux kernels (3.9+). 
+
+37) telnet-based monitor implemented.
+
+38) Package memory copy eliminated in traffic routing.
+
+39) Congestion avoidance implemented, for all protocols.
+
+40) Multi-tenant server implemented.
+
+41) Coturn project forked from rfc5766-turn-server.
+ 
+Things to be implemented in future (the development roadmap) 
+are described in the TODO file.

+ 128 - 0
TODO

@@ -0,0 +1,128 @@
+==================================================================
+
+###   I. PLATFORMS SUPPORT   ###
+
+==================================================================
+
+1) Fedora official package (turnserver or coturn ? TBD).
+
+2) MS Windows support.
+
+	Cygwin is supported. A "real" MS-Windows port would 
+	involve a usable GUI.
+
+==================================================================
+
+###   II. DOCS   ###
+
+==================================================================
+
+1) User's manual.
+
+2) Developer's manual.
+
+==================================================================
+
+###   III. NETWORK ENGINE   ###
+
+==================================================================
+
+1) Exclusive IP addresses for relay
+
+==================================================================
+
+###   IV. PERFORMANCE OPTIMIZATION   ###
+
+==================================================================
+
+1) A smarter load balancer has to be implemented.
+
+	The load balancer has to have a heartbeat channels with 
+	the slave servers, currently it is only just a dumb 
+	round-robin load distributor.
+
+2) For a large enterprise, a user-space stack to be integrated.
+
+	An another socket abstraction to be implemented, 
+	the one that uses the user-space TCP/IP stack with 
+	zero memory copy. This is an ambitious goal that would 
+	increase the system scaleability, significantly. 
+	The stock TCP/IP stack in UNIX and in MS Windows do not 
+	scale gracefully. We are trying to suppress those issues 
+	in the TURN Server, by using an advanced synchronous 
+	I/O technique, but still the underlying stock TCP/IP stack 
+	is a limitation.  
+	
+3) Multiple authentication threads.
+
+==================================================================
+
+###   V. SECURITY   ###
+
+==================================================================
+
+1) RADIUS integration ?
+
+2) Watch new TURN security draft. oAuth integration.
+
+==================================================================
+
+###   VI. STANDARDS SUPPORT   ###
+
+==================================================================
+
+1) Follow the draft ICE endpoint mobility standard and add changes 
+when necessary:
+
+   https://ietf.org/doc/draft-wing-mmusic-ice-mobility/
+
+2) For extra difficult NAT/FWs, consider implementing Websockets.
+
+3) MS TURN, MS STUN extensions.
+
+4) Bandwidth draft.
+
+5) ALPN with TLS and DTLS.
+
+6) Redirect draft.
+
+==================================================================
+
+###   VII. MISC FEATURES   ###
+
+==================================================================
+
+1) Locale support (?).
+
+	Currently we assume that all text data is 8-bits ASCII 
+	encoded, like C locale. It would be nice to support localized
+	strings (both 8-bits and 2-bytes). But I am not sure 
+	whether this is really important, given the essentially
+	backend nature of the TURN Server. The TURN server is so 
+	deeply "hidden" in the network infrastructure that the 
+	significant code complication may be unjustified.
+
+2) HTTP or GUI status monitor and management.
+
+	For enterprise users, a management (configuration, status 
+	and statistics) GUI has to be implemented. Currently, all 
+	these features are available through the shell command 
+	line, telnet client and through Redis command line.
+
+3) Traffic recording (for selected allocations).
+
+	That would be a helpful feature for a large enterprise 
+	(for testing and security purposes). 
+
+4) Ganglia monitoring.
+
+==================================================================
+
+###   VIII. CODING STUFF   ###
+
+==================================================================
+
+Nope
+
+==================================================================
+

+ 1063 - 0
configure

@@ -0,0 +1,1063 @@
+#!/bin/sh
+
+# Proprietary configure script of Coturn project
+
+cleanup() {
+	rm -rf ${TMPCPROGC}
+	rm -rf ${TMPCPROGB}
+	rm -rf ${TH_TMPCPROGC}
+	rm -rf ${TH_TMPCPROGB}
+	rm -rf ${DTLS_TMPCPROGC}
+	rm -rf ${DTLS_TMPCPROGB}
+	rm -rf ${PQ_TMPCPROGC}
+	rm -rf ${PQ_TMPCPROGB}
+	rm -rf ${MYSQL_TMPCPROGC}
+	rm -rf ${MYSQL_TMPCPROGB}
+	rm -rf ${D_TMPCPROGC}
+	rm -rf ${D_TMPCPROGB}
+	rm -rf ${E_TMPCPROGC}
+	rm -rf ${E_TMPCPROGO}
+	rm -rf ${HR_TMPCPROGC}
+	rm -rf ${HR_TMPCPROGB}
+	rm -rf ${TMPCADDRPROGO}
+}
+
+testlibraw() {
+    ${CC} ${TMPCPROGC} -o ${TMPCPROGB} ${OSCFLAGS} ${OSLIBS} -${1} 2>>/dev/null
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "Do not use -${1}"
+		return 0
+    else
+		OSLIBS="${OSLIBS} -${1}"
+		return 1
+    fi
+}
+
+testlibevent2_comp() {
+    ${CC} -c ${E_TMPCPROGC} -o ${E_TMPCPROGO} ${OSCFLAGS} 2>>/dev/null
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "Libevent2 development is not installed properly"
+		return 0
+    else
+		return 1
+    fi
+}
+
+testhiredis() {
+    HIREDISCFLAGS=
+    HIREDISLIBS=-lhiredis
+    ${CC} ${HR_TMPCPROGC} -o ${HR_TMPCPROGB} ${OSCFLAGS} ${DBLIBS} ${HIREDISCFLAGS} ${HIREDISLIBS} 2>>/dev/null
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+	${ECHO_CMD}
+	${ECHO_CMD} "HIREDIS DEVELOPMENT LIBRARY (libhiredis.*) AND/OR HEADERS (hiredis/*.h)"
+	${ECHO_CMD} "	ARE NOT INSTALLED PROPERLY ON THIS SYSTEM."
+	${ECHO_CMD} "	THAT'S OK BUT THE TURN SERVER IS BUILDING WITHOUT REDIS SUPPORT."
+	${ECHO_CMD}
+	return 0
+    else
+	DBCFLAGS="${DBCFLAGS} ${HIREDISCFLAGS}"
+	DBLIBS="${DBLIBS} ${HIREDISLIBS}"
+	return 1
+    fi
+}
+
+testlibpq() {
+    POSTCFLAGS="-I${PREFIX}/pgsql/include -I${PREFIX}/include/pgsql/ -I${PREFIX}/include/postgres/ -I${PREFIX}/postgres/include/ -I${PREFIX}/include/postgresql/ -I${PREFIX}/postgresql/include/"
+    POSTCFLAGS="${POSTCFLAGS} -I/usr/local/pgsql/include -I/usr/local/include/pgsql/ -I/usr/local/include/postgres/ -I/usr/local/postgres/include/ -I/usr/local/include/postgresql/ -I/usr/local/postgresql/include/"
+    POSTCFLAGS="${POSTCFLAGS} -I/usr/pgsql/include -I/usr/include/pgsql/ -I/usr/include/postgres/ -I/usr/postgres/include/ -I/usr/include/postgresql/ -I/usr/postgresql/include/"
+    for ilib in ${PREFIX}/pgsql/lib ${PREFIX}/lib/pgsql ${PREFIX}/lib64/pgsql /usr/local/pgsql/lib /usr/local/lib/pgsql /usr/local/lib64/pgsql /usr/pgsql/lib /usr/lib/pgsql /usr/lib64/pgsql ${PREFIX}/postgres/lib ${PREFIX}/lib/postgres ${PREFIX}/lib64/postgres /usr/local/postgres/lib /usr/local/lib/postgres /usr/local/lib64/postgres /usr/postgres/lib /usr/lib/postgres /usr/lib64/postgres ${PREFIX}/postgresql/lib ${PREFIX}/lib/postgresql ${PREFIX}/lib64/postgresql /usr/local/postgresql/lib /usr/local/lib/postgresql /usr/local/lib64/postgresql /usr/postgresql/lib /usr/lib/postgresql /usr/lib64/postgresql
+    do
+	if [ -d ${ilib} ] ; then
+    	    POSTLIBS="${POSTLIBS} -L${ilib}"
+	    if ! [ -z "${TURN_ACCEPT_RPATH}" ] ; then
+		TURN_RPATH="${TURN_RPATH} -Wl,-rpath,${ilib}"
+	    fi
+	fi
+    done
+    POSTLIBS="${OSLIBS} ${POSTLIBS} -lpq"
+    ${CC} ${PQ_TMPCPROGC} -o ${PQ_TMPCPROGB} ${OSCFLAGS} ${DBCFLAGS} ${POSTCFLAGS} ${DBLIBS} ${POSTLIBS} ${OSLIBS} 2>>/dev/null 
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+    	${ECHO_CMD}
+		${ECHO_CMD} "POSTGRESQL DEVELOPMENT LIBRARY (libpq.a) AND/OR HEADER (libpq-fe.h)"
+		${ECHO_CMD} "	ARE NOT INSTALLED PROPERLY ON THIS SYSTEM."
+		${ECHO_CMD} "	THAT'S OK BUT THE TURN SERVER IS BUILDING WITHOUT POSTGRESQL DATABASE SUPPORT."
+		${ECHO_CMD}
+		return 0
+    else
+		DBCFLAGS="${DBCFLAGS} ${POSTCFLAGS}"
+		DBLIBS="${DBLIBS} ${POSTLIBS}"
+		return 1
+    fi
+}
+
+testlibmysql() {
+    MYSQL_CFLAGS="-I${PREFIX}/mysql/include -I${PREFIX}/include/mysql/"
+    MYSQL_CFLAGS="${MYSQL_CFLAGS} -I/usr/local/mysql/include -I/usr/local/include/mysql/"
+    MYSQL_CFLAGS="${MYSQL_CFLAGS} -I/usr/mysql/include -I/usr/include/mysql/"
+    for ilib in ${PREFIX}/mysql/lib ${PREFIX}/lib/mysql ${PREFIX}/lib64/mysql /usr/local/mysql/lib /usr/local/lib/mysql /usr/local/lib64/mysql /usr/mysql/lib /usr/lib/mysql /usr/lib64/mysql
+    do
+      if [ -d ${ilib} ] ; then
+        MYSQL_LIBS="${MYSQL_LIBS} -L${ilib}"
+	if ! [ -z "${TURN_ACCEPT_RPATH}" ] ; then
+	    TURN_RPATH="${TURN_RPATH} -Wl,-rpath,${ilib}"
+	fi
+      fi
+    done
+    MYSQL_LIBS="${OSLIBS} ${MYSQL_LIBS} -lmysqlclient"
+    ${CC} ${MYSQL_TMPCPROGC} -o ${MYSQL_TMPCPROGB} ${OSCFLAGS} ${DBCFLAGS} ${DBLIBS} ${MYSQL_CFLAGS} ${MYSQL_LIBS} ${OSLIBS} 2>>/dev/null
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+    	${ECHO_CMD}
+		${ECHO_CMD} "MYSQL DEVELOPMENT LIBRARY (libmysqlclient) AND/OR HEADER (mysql.h)"
+		${ECHO_CMD} "	ARE NOT INSTALLED PROPERLY ON THIS SYSTEM."
+		${ECHO_CMD} "	THAT'S OK BUT THE TURN SERVER IS BUILDING WITHOUT MYSQL DATABASE SUPPORT."
+		${ECHO_CMD}
+		return 0
+    else
+		DBCFLAGS="${DBCFLAGS} ${MYSQL_CFLAGS}"
+		DBLIBS="${DBLIBS} ${MYSQL_LIBS}"
+		return 1
+    fi
+}
+
+testlib() {
+    testlibraw l${1}
+}
+
+pthread_testlib() {
+
+    SYSTEM=`uname`
+
+    if [ "${SYSTEM}" = "DragonFly" ] ; then
+	OSLIBS="${OSLIBS} -pthread"
+    fi
+
+    ISBSD=`uname | grep -i bsd`
+    if ! [ -z "${ISBSD}" ] ; then
+	OSLIBS="${OSLIBS} -pthread"
+    fi
+
+    if [ -z "${PTHREAD_LIBS}" ] ; then
+    	${CC} ${TH_TMPCPROGC} -o ${TH_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} 2>>/dev/null
+    	ER=$?
+    	if [ ${ER} -eq 0 ] ; then
+    		return 1
+    	else
+    		${CC} ${TH_TMPCPROGC} -o ${TH_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} -pthread 2>>/dev/null
+    		ER=$?
+    		if [ ${ER} -eq 0 ] ; then
+    			OSLIBS="${OSLIBS} -pthread"
+    			return 1
+    		else
+    			${CC} ${TH_TMPCPROGC} -o ${TH_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} -lpthread 2>>/dev/null
+    			ER=$?
+    			if [ ${ER} -eq 0 ] ; then
+    				OSLIBS="${OSLIBS} -lpthread"
+    				return 1
+				fi
+    		fi
+    	fi
+    else
+    	OSLIBS="${OSLIBS} ${PTHREAD_LIBS}"
+    fi
+		
+
+    ${CC} ${TH_TMPCPROGC} -o ${TH_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} 2>>/dev/null
+    ER=$?
+    if [ ${ER} -eq 0 ] ; then
+    	return 1
+    else
+    	${CC} ${TH_TMPCPROGC} -o ${TH_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} -D_GNU_SOURCE 2>>/dev/null
+    	ER=$?
+    	if [ ${ER} -eq 0 ] ; then
+	    	${ECHO_CMD} "Older GNU pthread library found"
+	    	OSCFLAGS="${OSCFLAGS} -D_GNU_SOURCE"
+	    	return 1
+	    else
+    		${ECHO_CMD} "Do not use pthreads" 
+		fi
+    fi
+    
+    return 0
+}
+
+pthread_testbarriers() {
+
+    ${ECHO_CMD} "pthread_barrier_t barrier;" >> ${TH_TMPCPROGC}
+    ${CC} ${TH_TMPCPROGC} -o ${TH_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} 2>>/dev/null
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "pthread barriers not found"
+		OSCFLAGS="${OSCFLAGS} -DTURN_NO_THREAD_BARRIERS"
+    fi
+}
+
+dtls_testlib() {
+
+    if [ -z "${TURN_NO_DTLS}" ] ; then
+    	${CC} ${DTLS_TMPCPROGC} -o ${DTLS_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} 2>>/dev/null
+    	ER=$?
+    	if [ ${ER} -eq 0 ] ; then
+    	    return 1
+    	else
+    	    return 0
+    	fi
+    else
+		return 0
+    fi
+}
+
+testdaemon() {
+
+	${CC} ${D_TMPCPROGC} -o ${D_TMPCPROGB} ${OSCFLAGS} ${OSLIBS} 2>>/dev/null
+	ER=$?
+	if [ ${ER} -eq 0 ] ; then
+	    OSCFLAGS="${OSCFLAGS} -DTURN_HAS_DAEMON"
+	fi
+}
+
+test_sin_len() {
+    TMPCADDRPROGC=src/client/ns_turn_ioaddr.c
+    ${CC} -c ${OSCFLAGS} -DTURN_HAS_SIN_LEN -Isrc ${TMPCADDRPROGC} -o ${TMPCADDRPROGO} 2>>/dev/null
+    ER=$?
+    if [ ${ER} -eq 0 ] ; then
+	OSCFLAGS="${OSCFLAGS} -DTURN_HAS_SIN_LEN"
+	${ECHO_CMD} "Sockets code is fine: sin_len field present"
+    else
+	${CC} -c ${OSCFLAGS} -Isrc ${TMPCADDRPROGC} -o ${TMPCADDRPROGO} 2>>/dev/null
+	ER=$?
+	if [ ${ER} -eq 0 ] ; then
+	    ${ECHO_CMD} "Sockets code is fine: no sin_len field present"
+	else
+	    ${ECHO_CMD} "WARNING: trial compilation failed: src/client/ns_turn_ioaddr.c"
+	fi
+    fi
+}
+
+#########################
+# Start
+#########################
+
+cleanup
+
+#########################
+# To be set:
+#########################
+
+if [ -z "${ECHO_CMD}" ] ; then
+	ECHO_CMD=echo 
+fi
+
+if [ -z "${PORTNAME}" ] ; then
+	PORTNAME=turnserver
+fi
+
+#########################
+
+# Installation directory options
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=BINDIR ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    BINDIR=$ac_optarg ;;
+
+  -datadir | --datadir | --datadi | --datad | -schemadir | --schemadir)
+    ac_prev=SCHEMADIR ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | -schemadir=* | --schemadir=*)
+    SCHEMADIR=$ac_optarg ;;
+
+  -docdir | --docdir | --docdi | --doc | --do | -docsdir | --docsdir | --docsdi | --docs)
+    ac_prev=DOCDIR ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=* | -docsdir=* | --docsdir=* | --docsdi=* | --docs=*)
+    DOCSDIR=$ac_optarg ;;
+
+  -examplesdir | --examplesdir | -examples | --examples)
+    ac_prev=EXAMPLESDIR ;;
+  -examplesdir=* | --examplesdir=* | -examples=* | --examples=*)
+    EXAMPLESDIR=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=INCLUDEDIR ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    INCLUDEDIR=$ac_optarg ;;
+
+  -turnincludedir | --turnincludedir)
+    ac_prev=TURNINCLUDEDIR ;;
+  -turnincludedir=* | --turnincludedir=*)
+    TURNINCLUDEDIR=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=LIBDIR ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    LIBDIR=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m | -manprefix | --manprefix)
+    ac_prev=MAXPREFIX ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=* | -manprefix=* | --manprefix=*)
+    MANPREFIX=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=PREFIX ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    PREFIX=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy | -confdir | --confdir)
+    ac_prev=CONFDIR ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=* | -confdir=* | --confdir=*)
+    CONFDIR=$ac_optarg ;;
+    
+  -disable-rpath | --disable-rpath)
+  	TURN_DISABLE_RPATH=1 ;;
+    
+  esac
+      
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+#############################################
+
+if [ -z "${PREFIX}" ] ; then
+
+	if [ -z "${prefix}" ] ; then
+
+		SYSTEM=`uname`
+
+		if [ "${SYSTEM}" = "NetBSD" ] ; then
+			# A little tough guy
+			PREFIX=/usr/pkg
+		elif [ "${SYSTEM}" = "SunOS" ] ; then
+			# A fat guy
+			PREFIX=/usr
+		else
+			# An ordinary person
+			PREFIX=/usr/local
+		fi
+	else
+		PREFIX=${prefix}
+	fi
+fi
+
+if [ -z "${BINDIR}" ] ; then
+    if [ -z "${bindir}" ] ; then
+	BINDIR=${PREFIX}/bin
+    else
+	BINDIR=${bindir}
+    fi
+fi
+
+if [ -z "${CONFDIR}" ] ; then
+    if [ -z "${confdir}" ] ; then
+	CONFDIR=${PREFIX}/etc
+    else
+	CONFDIR=${confdir}
+    fi
+fi
+
+if [ -z "${MANPREFIX}" ] ; then
+    if [ -z "${manprefix}" ] ; then
+	MANPREFIX=${PREFIX}
+    else
+	MANPREFIX=${manprefix}
+    fi
+fi
+
+if [ -z "${EXAMPLESDIR}" ] ; then
+    if [ -z "${examplesdir}" ] ; then
+	EXAMPLESDIR=${PREFIX}/share/examples/${PORTNAME}
+    else
+	EXAMPLESDIR=${examplesdir}
+    fi
+fi
+
+if [ -z "${DOCSDIR}" ] ; then
+    if [ -z "${docsdir}" ] ; then
+	DOCSDIR=${PREFIX}/share/doc/${PORTNAME}
+    else
+	DOCSDIR=${docsdir}
+    fi
+fi
+
+if [ -z "${LIBDIR}" ] ; then
+    if [ -z "${libdir}" ] ; then
+	LIBDIR=${PREFIX}/lib
+    else
+	LIBDIR=${libdir}
+    fi
+fi
+
+if [ -z "${SCHEMADIR}" ] ; then
+    if [ -z "${schemadir}" ] ; then
+	SCHEMADIR=${PREFIX}/share/${PORTNAME}
+    else
+	SCHEMADIR=${schemadir}
+    fi
+fi
+
+if [ -z "${INCLUDEDIR}" ] ; then
+    if [ -z "${includedir}" ] ; then
+	INCLUDEDIR=${PREFIX}/include
+    else
+	INCLUDEDIR=${includedir}
+    fi
+fi
+
+if [ -z "${TURNINCLUDEDIR}" ] ; then
+    if [ -z "${turnincludedir}" ] ; then
+	TURNINCLUDEDIR=${INCLUDEDIR}/turn
+    else
+	TURNINCLUDEDIR=${turnincludedir}
+    fi
+fi
+
+###############################################
+
+if [ -z "${ARCHIVERCMD}" ] ; then
+	ARCHIVERCMD="ar -r"
+fi
+
+if [ -z "${MORECMD}" ]; then
+	type more 2>>/dev/null
+	ER=$?
+	if [ ${ER} -eq 0 ] ; then
+		MORECMD="more"
+	else
+		type less 2>>/dev/null
+		ER=$?
+		if [ ${ER} -eq 0 ] ; then
+			MORECMD="less"
+		else
+			MORECMD="cat"
+		fi
+	fi
+fi
+
+OSCFLAGS="-I${INCLUDEDIR} -I${PREFIX}/include/ -I/usr/local/include ${CFLAGS}"
+OSLIBS="${LDFLAGS}"
+for ilib in ${PREFIX}/lib/event2/ ${PREFIX}/lib/ /usr/local/lib/event2/ /usr/local/lib/ ${PREFIX}/lib64/event2/ ${PREFIX}/lib64/ /usr/local/lib64/event2/ /usr/local/lib64/ 
+do
+    if [ -d ${ilib} ] ; then
+		OSLIBS="${OSLIBS} -L${ilib}"
+		TURN_RPATH="${TURN_RPATH} -Wl,-rpath,${ilib}"
+    fi
+done
+
+SYSTEM=`uname`
+if [ "${SYSTEM}" = "NetBSD" ] ; then
+	OSCFLAGS="${OSCFLAGS} -I/usr/pkg/include"
+	OSLIBS="-L/usr/pkg/lib ${OSLIBS}"
+	if ! [ -z "${TURN_ACCEPT_RPATH}" ] ; then
+	    TURN_RPATH="${TURN_RPATH} -Wl,-rpath,/usr/pkg/lib"
+	fi
+fi
+
+###########################
+# Install shell commands
+###########################
+
+type ginstall 2>>/dev/null
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+	INSTALL_PROGRAM="ginstall"
+	INSTALL_MAN="ginstall"
+	INSTALL_SCRIPT="ginstall"
+	INSTALL_SHARED_LIB="ginstall"
+	INSTALL_STATIC_LIB="ginstall"
+	INSTALL_DATA="ginstall"
+	MKDIR="ginstall -d"
+else
+	type install 2>>/dev/null
+	ER=$?
+	if [ ${ER} -eq 0 ] ; then
+		INSTALL_PROGRAM="install"
+		INSTALL_MAN="install"
+		INSTALL_SCRIPT="install"
+		INSTALL_SHARED_LIB="install"
+		INSTALL_STATIC_LIB="install"
+		INSTALL_DATA="install"
+		MKDIR="install -d"
+	else
+		INSTALL_PROGRAM="cp -pf"
+		INSTALL_MAN="cp -pf"
+		INSTALL_SCRIPT="cp -pf"
+		INSTALL_SHARED_LIB="cp -pf"
+		INSTALL_STATIC_LIB="cp -pf"
+		INSTALL_DATA="cp -pf"
+		MKDIR="mkdir -p"
+	fi
+fi
+
+type pkill 2>>/dev/null
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+	PKILL_PROGRAM="pkill"
+else
+	PKILL_PROGRAM="${ECHO_CMD}"
+fi
+
+INSTALL_DIR="cp -rpf"
+MKBUILDDIR="mkdir -p"
+RMCMD="rm -rf"
+
+#############################
+# Adjustments for Solaris
+#############################
+
+SYSTEM=`uname`
+
+if [ "${SYSTEM}" = "SunOS" ] ; then
+# Solaris ? is this you ?!
+    OSCFLAGS="${OSCFLAGS} -D__EXTENSIONS__ -D_XOPEN_SOURCE=500"
+fi
+
+#########################
+# Temporary DIR location:
+#########################
+
+TMPDIR="."
+
+if [ -d /var/tmp ] ; then
+  TMPDIR="/var/tmp"
+elif [ -d /tmp ] ; then
+  TMPDIR=/tmp
+fi
+
+${ECHO_CMD} Use TMP dir ${TMPDIR}
+
+#########################
+# Basic C test programs
+#########################
+
+TMPCADDRPROGO=${TMPDIR}/__test__ccomp_addr_$$.o
+
+TMPCPROG=__test__ccomp__$$
+TMPCPROGC=${TMPDIR}/${TMPCPROG}.c
+TMPCPROGB=${TMPDIR}/${TMPCPROG}
+
+cat > ${TMPCPROGC} <<!
+#include <stdlib.h>
+int main(int argc, char** argv) {
+    return (int)(argv[argc][0]);
+}
+!
+
+TH_TMPCPROG=__test__ccomp__pthread__$$
+TH_TMPCPROGC=${TMPDIR}/${TH_TMPCPROG}.c
+TH_TMPCPROGB=${TMPDIR}/${TH_TMPCPROG}
+
+cat > ${TH_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <pthread.h>
+int main(int argc, char** argv) {
+    pthread_mutexattr_settype(0,PTHREAD_MUTEX_RECURSIVE);
+    return (int)pthread_create(0,0,0,0)+(int)(argv[argc][0]);
+}
+
+!
+
+DTLS_TMPCPROG=__test__ccomp__dtls__$$
+DTLS_TMPCPROGC=${TMPDIR}/${DTLS_TMPCPROG}.c
+DTLS_TMPCPROGB=${TMPDIR}/${DTLS_TMPCPROG}
+
+cat > ${DTLS_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+int main(int argc, char** argv) {
+    return (((int)(BIO_CTRL_DGRAM_QUERY_MTU)) + argc + (int)(argv[argc][0]) + DTLSv1_listen(NULL,NULL));
+}
+!
+
+D_TMPCPROG=__test__ccomp__daemon__$$
+D_TMPCPROGC=${TMPDIR}/${D_TMPCPROG}.c
+D_TMPCPROGB=${TMPDIR}/${D_TMPCPROG}
+
+cat > ${D_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <unistd.h>
+int main(int argc, char** argv) {
+    return (int)daemon(0,0)+(int)(argv[argc][0]);
+}
+!
+
+E_TMPCPROG=__test__ccomp__libevent2__$$
+E_TMPCPROGC=${TMPDIR}/${E_TMPCPROG}.c
+E_TMPCPROGO=${TMPDIR}/${E_TMPCPROG}.o
+
+cat > ${E_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <event2/event.h>
+int main(int argc, char** argv) {
+    return (int)(argv[argc][0]);
+}
+!
+
+HR_TMPCPROG=__test__ccomp__hiredis__$$
+HR_TMPCPROGC=${TMPDIR}/${HR_TMPCPROG}.c
+HR_TMPCPROGB=${TMPDIR}/${HR_TMPCPROG}
+
+cat > ${HR_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <hiredis/hiredis.h>
+#include <hiredis/async.h>
+int main(int argc, char** argv) {
+	redisAsyncHandleRead(NULL);
+    return (int)(argv[argc][0]);
+}
+!
+
+PQ_TMPCPROG=__test__ccomp__libpq__$$
+PQ_TMPCPROGC=${TMPDIR}/${PQ_TMPCPROG}.c
+PQ_TMPCPROGB=${TMPDIR}/${PQ_TMPCPROG}
+
+cat > ${PQ_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <libpq-fe.h>
+int main(int argc, char** argv) {
+    return (argc+(PQprotocolVersion(NULL))+(int)(argv[0][0]));
+}
+!
+
+MYSQL_TMPCPROG=__test__ccomp__libmysql__$$
+MYSQL_TMPCPROGC=${TMPDIR}/${MYSQL_TMPCPROG}.c
+MYSQL_TMPCPROGB=${TMPDIR}/${MYSQL_TMPCPROG}
+
+cat > ${MYSQL_TMPCPROGC} <<!
+#include <stdlib.h>
+#include <mysql.h>
+int main(int argc, char** argv) {
+    return (argc+
+    	(int)(mysql_real_connect(NULL, NULL, NULL, NULL, NULL, 0, NULL, 0)!=0)+
+    	(int)(argv[0][0]));
+}
+!
+
+##########################
+# What is our compiler ?
+##########################
+
+if [ -z "${CC}" ] ; then
+    CC=cc
+    ${CC} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+	ER=$?
+	if ! [ ${ER} -eq 0 ] ; then
+		CC=gcc
+    	${CC} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+		ER=$?
+		if ! [ ${ER} -eq 0 ] ; then
+			CC=clang
+    		${CC} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+			ER=$?
+			if ! [ ${ER} -eq 0 ] ; then
+				CC=unknown
+			fi
+		fi
+	fi
+fi
+
+${ECHO_CMD} "Compiler: ${CC}"
+
+if [ -z "${TURN_ACCEPT_RPATH}" ] ; then
+    ${CC} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} -Wl,-rpath,/usr/lib 2>>/dev/null
+    ER=$?
+    if [ ${ER} -eq 0 ] ; then
+	TURN_ACCEPT_RPATH=1
+    fi
+fi
+
+${CC} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    ${ECHO_CMD} "ERROR: cannot use compiler ${CC} properly"
+    cleanup
+    exit
+fi
+
+###########################
+# Check if we can use GNU
+# or Clang compiler flags
+###########################
+
+GNUOSCFLAGS="-g ${GNUOSCFLAGS}"
+GNUOSCFLAGS="${GNUOSCFLAGS} -Wall -Wno-deprecated-declarations -Wextra -Wformat-security -Wnested-externs -Wstrict-prototypes  -Wmissing-prototypes -Wpointer-arith -Wcast-qual"
+GNUOSCFLAGS="${GNUOSCFLAGS} -Wno-write-strings"
+
+${CC} -Werror ${GNUOSCFLAGS} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    ${ECHO_CMD} "Hm..."
+    ${CC} -Wall ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "Not an ordinary GNU or Clang compiler"
+    else
+		${ECHO_CMD} "g++ or something..."
+		GNUOSCFLAGS="-g -Wall -Wno-deprecated-declarations -Wextra -Wformat-security -Wpointer-arith -Wcast-qual -Wno-write-strings"
+		${CC} -Werror ${GNUOSCFLAGS} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+		ER=$?
+		if ! [ ${ER} -eq 0 ] ; then
+	    	${ECHO_CMD} "Not an ordinary g++ compiler"
+	    	GNUOSCFLAGS="-x c++ -g -Wall -Wno-deprecated-declarations -Wextra -Wformat-security -Wpointer-arith -Wcast-qual -Wno-write-strings"
+	    	${CC} -Werror ${GNUOSCFLAGS} ${TMPCPROGC} ${OSCFLAGS} -o ${TMPCPROGB} 2>>/dev/null
+	    	ER=$?
+	    	if ! [ ${ER} -eq 0 ] ; then
+	    		${ECHO_CMD} "Not an ordinary c++ compiler"
+	    	else
+				${ECHO_CMD} "Clang++ compiler ?"
+	    		OSCFLAGS="${GNUOSCFLAGS} ${OSCFLAGS}"
+	    	fi
+		else
+	    	OSCFLAGS="${GNUOSCFLAGS} ${OSCFLAGS}"
+		fi
+    fi
+else
+    OSCFLAGS="${GNUOSCFLAGS} ${OSCFLAGS}"
+fi
+
+###########################
+# Test some general-purpose
+# libraries 
+###########################
+
+testlib socket
+testlib nsl
+testlib dl
+testlib rt
+testlib wldap32
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "CYGWIN ?"
+fi
+testlib wldap64
+testlib intl
+
+###########################
+# Test sockets compilation
+###########################
+
+test_sin_len
+
+###########################
+# Can we use multi-threading ?
+###########################
+
+pthread_testlib
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+	${ECHO_CMD} "ERROR: Cannot find pthread library functions."
+	exit
+fi
+
+if [ -z ${TURN_NO_THREAD_BARRIERS} ] ; then 
+	pthread_testbarriers
+else 
+	TURN_NO_THREAD_BARRIERS="-DTURN_NO_THREAD_BARRIERS"
+fi
+
+if [ -z ${TURN_IP_RECVERR} ] ; then 
+	${ECHO_CMD} "Ignore IP_RECVERR"
+else 
+	${ECHO_CMD} "Use IP_RECVERR"
+	TURN_IP_RECVERR="-DTURN_IP_RECVERR"
+	OSCFLAGS="${OSCFLAGS} ${TURN_IP_RECVERR}"
+fi
+
+###########################
+# Can we use daemon ?
+###########################
+
+testdaemon
+
+###########################
+# Test OpenSSL installation
+###########################
+
+testlib crypto
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    ${ECHO_CMD} "Crypto SSL lib found."
+else
+    ${ECHO_CMD} "ERROR: OpenSSL Crypto development libraries are not installed properly in required location."
+    ${ECHO_CMD} "Abort."
+    cleanup
+    exit
+fi
+
+testlib ssl
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    ${ECHO_CMD} "SSL lib found."
+else
+    ${ECHO_CMD} "ERROR: OpenSSL development libraries are not installed properly in required location."
+    ${ECHO_CMD} "Abort."
+    cleanup
+    exit
+fi
+
+###########################
+# Can we use DTLS ?
+###########################
+
+if [ -z ${TURN_NO_DTLS} ] ; then 
+
+dtls_testlib
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+	${ECHO_CMD} "WARNING: Cannot find DTLS support."
+	${ECHO_CMD} "Turning DTLS off."
+	TURN_NO_DTLS="-DTURN_NO_DTLS"
+fi
+
+else
+	TURN_NO_DTLS="-DTURN_NO_DTLS"
+fi
+
+###########################
+# Test Libevent2 setup
+###########################
+testlibevent2_comp
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    ${ECHO_CMD} "Libevent2 development found."
+else
+    ${ECHO_CMD} "ERROR: Libevent2 development libraries are not installed properly in required location."
+    ${ECHO_CMD} "ERROR: may be you have just too old libevent tool - then you have to upgrade it."
+    ${ECHO_CMD} "See the INSTALL file."
+    ${ECHO_CMD} "Abort."
+    cleanup
+    exit
+fi
+
+testlib event_core
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    testlib event_extra
+    ${ECHO_CMD} "Libevent2 runtime found."
+else
+    testlib event
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "Libevent2 runtime found."
+    else
+		${ECHO_CMD} "ERROR: Libevent2 runtime libraries are not installed properly in required location."
+		${ECHO_CMD} "See the INSTALL file."
+		${ECHO_CMD} "Abort."
+		cleanup
+		exit
+    fi
+fi
+
+if [ -z "${TURN_NO_TLS}" ] ; then
+
+	testlib event_openssl
+	ER=$?
+	if ! [ ${ER} -eq 0 ] ; then
+    	${ECHO_CMD} "Libevent2 openssl found."
+	else
+    	${ECHO_CMD} "ERROR: Libevent2 development libraries are not compiled with OpenSSL support."
+    	${ECHO_CMD} "TLS will be disabled."
+    	TURN_NO_TLS="-DTURN_NO_TLS"
+	fi
+
+else
+	TURN_NO_TLS="-DTURN_NO_TLS"
+fi
+
+testlib event_pthreads
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+	${ECHO_CMD} "Libevent2 pthreads found."
+else
+   	${ECHO_CMD} "ERROR: Libevent2 development libraries are not compiled with threads support."
+	exit
+fi
+
+###########################
+# Test PostgreSQL
+###########################
+
+if [ -z "${TURN_NO_PQ}" ] ; then
+
+	testlibpq
+	ER=$?
+	if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "PostgreSQL found."
+	else
+		TURN_NO_PQ="-DTURN_NO_PQ"
+	fi
+else
+	TURN_NO_PQ="-DTURN_NO_PQ"
+fi
+
+###########################
+# Test MySQL
+###########################
+
+if [ -z "${TURN_NO_MYSQL}" ] ; then
+
+	testlibmysql
+	ER=$?
+	if ! [ ${ER} -eq 0 ] ; then
+		${ECHO_CMD} "MySQL found."
+	else
+		TURN_NO_MYSQL="-DTURN_NO_MYSQL"
+	fi
+else
+	TURN_NO_MYSQL="-DTURN_NO_MYSQL"
+fi
+
+###########################
+# Test Redis
+###########################
+
+if [ -z "${TURN_NO_HIREDIS}" ] ; then
+
+	testhiredis
+
+	ER=$?
+	if ! [ ${ER} -eq 0 ] ; then
+  		${ECHO_CMD} "Hiredis found."
+	else
+  		TURN_NO_HIREDIS="-DTURN_NO_HIREDIS"
+	fi
+
+else
+	TURN_NO_HIREDIS="-DTURN_NO_HIREDIS"
+
+fi
+
+###############################
+# LDCONFIG
+###############################
+
+if [ -z "${LDCONFIG}" ] ; then
+	ISBSD=`uname | grep -i bsd`
+	if [ -z "${ISBSD}" ] ; then
+		ISLINUX=`uname | grep -i linux`
+		if [ -z "${ISLINUX}" ] ; then 
+			SYSTEM=`uname`
+			if [ "${SYSTEM}" = "SunOS" ] ; then
+				LDCONFIG="crle -u -l"
+			else
+				LDCONFIG=${ECHO_CMD}
+			fi
+		else
+			LDCONFIG="ldconfig -n"
+		fi
+	else
+		LDCONFIG="ldconfig -m"
+	fi
+fi
+
+
+###############################
+# So, what we have now:
+###############################
+
+OSCFLAGS="${OSCFLAGS} ${TURN_NO_THREAD_BARRIERS} ${TURN_NO_DTLS} ${TURN_NO_TLS} -DINSTALL_PREFIX=${PREFIX}"
+
+if ! [ -z "${TURN_ACCEPT_RPATH}" ] ; then
+  if [ -z "${TURN_DISABLE_RPATH}" ] ; then
+    TURN_RPATH="${TURN_RPATH} -Wl,-rpath,/usr/local/lib"
+    OSLIBS="${OSLIBS} ${TURN_RPATH}"
+  fi
+fi
+
+${ECHO_CMD} PREFIX="${PREFIX}" OSLIBS="${OSLIBS}" DBLIBS="${DBLIBS}" OSCFLAGS="${OSCFLAGS}" DBCFLAGS="${DBCFLAGS}" $@
+
+###############################
+# Make make:
+###############################
+
+${ECHO_CMD} "#################################" > Makefile
+${ECHO_CMD} "# Generated by configure script #" >> Makefile
+${ECHO_CMD} "#################################" >> Makefile
+${ECHO_CMD} "ECHO_CMD = ${ECHO_CMD}" >> Makefile
+${ECHO_CMD} "CC = ${CC}" >> Makefile
+${ECHO_CMD} "LDFLAGS += ${OSLIBS}" >> Makefile
+${ECHO_CMD} "DBLIBS += ${DBLIBS}" >> Makefile
+${ECHO_CMD} "CFLAGS += ${OSCFLAGS}" >> Makefile
+${ECHO_CMD} "CPPFLAGS = ${CPPFLAGS}" >> Makefile
+${ECHO_CMD} "DBCFLAGS += ${DBCFLAGS} ${TURN_NO_PQ} ${TURN_NO_MYSQL} ${TURN_NO_HIREDIS}" >> Makefile
+${ECHO_CMD} "#" >> Makefile
+${ECHO_CMD} "PORTNAME = ${PORTNAME}" >> Makefile
+${ECHO_CMD} "PREFIX = ${PREFIX}" >> Makefile
+${ECHO_CMD} "prefix = ${PREFIX}" >> Makefile
+${ECHO_CMD} "BINDIR = ${BINDIR}" >> Makefile
+${ECHO_CMD} "bindir = ${BINDIR}" >> Makefile
+${ECHO_CMD} "CONFDIR = ${CONFDIR}" >> Makefile
+${ECHO_CMD} "confdir = ${CONFDIR}" >> Makefile
+${ECHO_CMD} "MANPREFIX = ${MANPREFIX}" >> Makefile
+${ECHO_CMD} "manprefix = ${MANPREFIX}" >> Makefile
+${ECHO_CMD} "EXAMPLESDIR = ${EXAMPLESDIR}" >> Makefile
+${ECHO_CMD} "examplesdir = ${EXAMPLESDIR}" >> Makefile
+${ECHO_CMD} "DOCSDIR = ${DOCSDIR}" >> Makefile
+${ECHO_CMD} "docsdir = ${DOCSDIR}" >> Makefile
+${ECHO_CMD} "LIBDIR = ${LIBDIR}" >> Makefile
+${ECHO_CMD} "libdir = ${LIBDIR}" >> Makefile
+${ECHO_CMD} "SCHEMADIR = ${SCHEMADIR}" >> Makefile
+${ECHO_CMD} "schemadir = ${SCHEMADIR}" >> Makefile
+${ECHO_CMD} "INCLUDEDIR = ${INCLUDEDIR}" >> Makefile
+${ECHO_CMD} "includedir = ${INCLUDEDIR}" >> Makefile
+${ECHO_CMD} "TURNINCLUDEDIR = ${TURNINCLUDEDIR}" >> Makefile
+${ECHO_CMD} "turnincludedir = ${TURNINCLUDEDIR}" >> Makefile
+${ECHO_CMD} "#" >> Makefile
+${ECHO_CMD} "ARCHIVERCMD = ${ARCHIVERCMD}" >> Makefile
+${ECHO_CMD} "MKDIR = ${MKDIR}" >> Makefile
+${ECHO_CMD} "INSTALL_PROGRAM = ${INSTALL_PROGRAM}" >> Makefile
+${ECHO_CMD} "PKILL_PROGRAM = ${PKILL_PROGRAM}" >> Makefile
+${ECHO_CMD} "INSTALL_MAN = ${INSTALL_MAN}" >> Makefile
+${ECHO_CMD} "INSTALL_SCRIPT = ${INSTALL_SCRIPT}" >> Makefile
+${ECHO_CMD} "INSTALL_SHARED_LIB = ${INSTALL_SHARED_LIB}" >> Makefile
+${ECHO_CMD} "INSTALL_STATIC_LIB = ${INSTALL_STATIC_LIB}" >> Makefile
+${ECHO_CMD} "INSTALL_DATA = ${INSTALL_DATA}" >> Makefile
+${ECHO_CMD} "INSTALL_DIR = ${INSTALL_DIR}" >> Makefile
+${ECHO_CMD} "MKBUILDDIR = ${MKBUILDDIR}" >> Makefile
+${ECHO_CMD} "RMCMD = ${RMCMD}" >> Makefile
+${ECHO_CMD} "MORECMD = ${MORECMD}" >> Makefile
+${ECHO_CMD} "LDCONFIG=${LDCONFIG}" >> Makefile
+${ECHO_CMD} "################################" >> Makefile
+${ECHO_CMD} "" >> Makefile
+cat Makefile.in >> Makefile
+
+###############################
+# End:
+###############################
+
+cleanup
+
+

+ 23 - 0
examples/etc/turn_client_cert.pem

@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDzjCCArYCCQD3YHhln4EqhDANBgkqhkiG9w0BAQUFADCBpzELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAkNBMRUwEwYDVQQHEwxXYWxudXQgQ3JlZWsxKzApBgNVBAoT
+IlJGQzU3NjYgVFVSTiBTZXJ2ZXIgcHVibGljIHByb2plY3QxFDASBgNVBAsTC2Rl
+dmVsb3BtZW50MQ0wCwYDVQQDEwRPbGVnMSIwIAYJKoZIhvcNAQkBFhNtb20wNDAy
+NjdAZ21haWwuY29tMCAXDTEyMTEyNzAwNDEwNVoYDzIxMTIxMTAzMDA0MTA1WjCB
+pzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRUwEwYDVQQHEwxXYWxudXQgQ3Jl
+ZWsxKzApBgNVBAoTIlJGQzU3NjYgVFVSTiBTZXJ2ZXIgcHVibGljIHByb2plY3Qx
+FDASBgNVBAsTC2RldmVsb3BtZW50MQ0wCwYDVQQDEwRPbGVnMSIwIAYJKoZIhvcN
+AQkBFhNtb20wNDAyNjdAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEA3huHvPYyvNZBK91bP3O1dBdOj93YQ3812BTcRMjEYnvSyyEosxFd
+dEnILgDiFK//pFnDtwm7FxOCtVwRQ0+8qGTH4vH0EIpKTBsaafKH3L9CYe40pwcm
+BJHvclOa4vl2Ghi09+M0UEHdokkM77K9rpXx7aZILoICkqnoAuBe0TY8D5PBXinM
+gtk7HlrvANxSmPHAAaGQ5t/+jfTWVH1UYCpogTgCKYPbNi+joKu6oEz+qRKAqDYd
+FY6/Qpiv7reYiNiVhM7HGNY27FkKDJDBhsmZRmtTIEdYFfcWPZvv69L7Rf1skOXF
+Vm5/to3HArJJF+lz6YGj0C3pE6dZt6sUmQIDAQABMA0GCSqGSIb3DQEBBQUAA4IB
+AQAhXgGdXXf0dMPdkfl4jv4dqFNSmax6wmeNc+oJC9qIFVDLsdAaAWXZ+pZHYIMR
+UN8mQobsIZdfPQ0gs8CgUwrKziAjA92y2Q/I7vsg83qRLhysGC5etYMD/wlySDDS
+AJKraevDPTEdmfNstCblubNG2PIeqV1isWtPMqB2dMsCeyzJXVyfD0QcABzFv4Fs
+MMy7JI7MsctNh1tjV/0TsddDMeMLs22rix5fS8MZ6uunFzIuJ0MshFNehXFuvz0B
+uNmn0k7djUm3h+2Avs3YGCo/8GtqHapc/lva/9gT+iEW0e7i0Ru5Jhar66VMzJqv
++wEhQafC77d3vWHtXQU8dYmM
+-----END CERTIFICATE-----

+ 27 - 0
examples/etc/turn_client_pkey.pem

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA3huHvPYyvNZBK91bP3O1dBdOj93YQ3812BTcRMjEYnvSyyEo
+sxFddEnILgDiFK//pFnDtwm7FxOCtVwRQ0+8qGTH4vH0EIpKTBsaafKH3L9CYe40
+pwcmBJHvclOa4vl2Ghi09+M0UEHdokkM77K9rpXx7aZILoICkqnoAuBe0TY8D5PB
+XinMgtk7HlrvANxSmPHAAaGQ5t/+jfTWVH1UYCpogTgCKYPbNi+joKu6oEz+qRKA
+qDYdFY6/Qpiv7reYiNiVhM7HGNY27FkKDJDBhsmZRmtTIEdYFfcWPZvv69L7Rf1s
+kOXFVm5/to3HArJJF+lz6YGj0C3pE6dZt6sUmQIDAQABAoIBAH5ITN8FZEe10gws
+qUrkcRD2h3aI/gMyetzGz45UUERmfq17xvY5M1eA884kNmbowoMhfoO9hqBSOYkA
+Ndh9p5he5L+GLeyRlDi9WEFQ4iqCnC2uEEW/bMBAcVIhcvkGOT4ROiOPDRlsuaUh
+v7cxe2OeYZVra7L1vJzC+eVYyNBN5CgK8w08MPEkupQS9+Jvr0QWCikRz187cG45
+EiDMrBKyJNE9lY6u4P8gJ+/NgaASWP/D3kbsjiQ2OwSGLrwDAvWC7Bx2GK3/0goA
+btp7YGaWvp+mE5V91cOW+PfweC5Do4MjOr4ToNkczW0AxKE5o94yo56h+II5bX6N
+z65VvtkCgYEA/Sq/3S2yup/Oodzj003KG4skWYFrj7KXeXgm7RZcpNwkd8JaFXJ/
+Cwl7/3bkRv6RHLmXX/2hcNWlxq3u6Efs1EjtycdArU68kO01vLdExJYIzHKmHikV
+n+T4hukxGDzObxn3lH1KcOodh/x572Uufn79dewoZCPzH8t/jiMOWGcCgYEA4JfN
+66Kq/oDookqenM9Ij5l6zeeNwzMjIlkU2eG0DAH0KdsBN/hTGGGRQVBk03YREQmK
+crEhGAZxzfrX5fK11UVG3C2pqAtrVe6FuD32vFUpP1MO0ftSA889NoEwGdNZV4pV
+Mk0+6xVCNOatj2inMXlQq5s68WfCzkiWD7uLCv8CgYBcwuYsF4tuYBGpMzNzAAS2
+1OPLu+T6cPiZdFHm+xOVAGiITPkO9LXiCGabsydvb+UhvkrdzCP0IQQt6RsplvkK
+y3H9RfnHxprHC3NuI0SaN1Mf/j4pvOoEfTQm0pi/hcAp6zzQ9ptpBg8t/W98LPm9
+NbCPHamrD5UMqFajcOrXrwKBgD8D2M8IcRm/aYY/kYlFz4Ia+g3Trj7alj0I6YTI
+gw/rbGph/FGL5ySsG2lL+T4rnlY9aw8LC9IF3OCCRRlLpCEWsu8MENIJgjA2IGa1
+XAkzi8MstrfL4BMZjn9AeBKG7kZVldnrOoATEuRs5L2cC20iMLQ1dbBOAKaITzJS
+2IxZAoGBAKqwr/uennxJrnMtpjLBgcphoU3aXJZvzzDqlOaqzJp6Xmbese4sDEe0
+hvVHreigDzOnGnqL/vSjTDWaLqS/O1iE7p+UrGIkZj/Zl6Jk54OX6AHmWE2LhdlU
+FYgIQKX7fuocpF1Dpe7xEeVwvdp+UqbDzHQg1CWGe1cBPYDYIkSH
+-----END RSA PRIVATE KEY-----

+ 22 - 0
examples/etc/turn_server_cert.pem

@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDsDCCApgCCQCmgrJCiQlGOTANBgkqhkiG9w0BAQUFADCBmDELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAkNBMRUwEwYDVQQHEwxXYWxudXQgQ3JlZWsxHDAaBgNVBAoT
+E1RVUk4gU2VydmVyIHByb2plY3QxFDASBgNVBAsTC0RldmVsb3BtZW50MQ0wCwYD
+VQQDEwRPbGVnMSIwIAYJKoZIhvcNAQkBFhNtb20wNDAyNjdAZ21haWwuY29tMCAX
+DTEyMTEyNTA4MjAxNloYDzIxMTIxMTAxMDgyMDE2WjCBmDELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgTAkNBMRUwEwYDVQQHEwxXYWxudXQgQ3JlZWsxHDAaBgNVBAoTE1RV
+Uk4gU2VydmVyIHByb2plY3QxFDASBgNVBAsTC0RldmVsb3BtZW50MQ0wCwYDVQQD
+EwRPbGVnMSIwIAYJKoZIhvcNAQkBFhNtb20wNDAyNjdAZ21haWwuY29tMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv6bYkERhZ43RjW4EuqCaTq5g+D+l
+JI/GwlVzdzQ3+F4clMQDR1kp1nX+9AvwjCXz3AYwY1H9CqjmjGM4R9uNJJseK/aJ
+d2DUFADkF+7I674XwX8U2Fy5on9jqWq3jdbb8eg/awcTBdrNLWNPquwfS2KVdooj
+9yPkqnO0c3ko1/OzIQCcs09O3l/MPt+aOsHk3B9l79ZRs3zWkylI+we0Fnc+7tZE
+psCztA+KCCoiJf7NenOvVhdKg7D1AXuzJ/P/Euvc3+CIiS9HI4pWLopY1k+HydLe
+IcopqSbg9CRIKe1HOL8YTvCm2ZoTqgijwWUlGtwEDf2xxUQX/TLYiW8JFQIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4IBAQATbrBOLV4e8Qmsby9+srxXsdbNc60PmDZ4WiZ1
+IElfWmzM7wGXm9sJg1PX/7T24R1tbwZGLIhZnkhecG372GChULZJ9Pdjh0Ab2nK5
+LRKHXTpjp/xOJvx0JMCIIyRnGZT1nABPOk8uEjNW8PaU6yhQ4f5nKaSOgYGRCln6
+dcy5vylCsyD9Q7GXs0KOC38XD+Ycv6VLX4zKJ2Yum50Wt643nLjG9RlGT3FXWJ1K
+HUbPC5TO6bcYLdiTjaYr+X8xC/x6h/Ngdo/16w7fRmQQ4uS+TVXrg8ITmI71KX/I
+m7C9jbsubwzrhW84oZXYf+o/0ATtEAhiVLnHifKCCYikqfVj
+-----END CERTIFICATE-----

+ 27 - 0
examples/etc/turn_server_pkey.pem

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAv6bYkERhZ43RjW4EuqCaTq5g+D+lJI/GwlVzdzQ3+F4clMQD
+R1kp1nX+9AvwjCXz3AYwY1H9CqjmjGM4R9uNJJseK/aJd2DUFADkF+7I674XwX8U
+2Fy5on9jqWq3jdbb8eg/awcTBdrNLWNPquwfS2KVdooj9yPkqnO0c3ko1/OzIQCc
+s09O3l/MPt+aOsHk3B9l79ZRs3zWkylI+we0Fnc+7tZEpsCztA+KCCoiJf7NenOv
+VhdKg7D1AXuzJ/P/Euvc3+CIiS9HI4pWLopY1k+HydLeIcopqSbg9CRIKe1HOL8Y
+TvCm2ZoTqgijwWUlGtwEDf2xxUQX/TLYiW8JFQIDAQABAoIBADUPHCXUyKLCwKFH
+NEf27sGZxX71H+NfaseioLT/3/8DDyagncfDB7I4OL2YEKC8YScpD3xv1n59BFcZ
+oRtDzW+1AkVpm+VRCWYAWSXHFhkuJ6WKaVr9UOeMHStqQCcktP/kLKqU6s9UJDnM
+pOHNPVzBjl+jHxHs/gGyxuKxSH2Anwkrzpiv5j0obKFnw3QtAqeZRs1NlvPtYt2S
+eihZWr8r8LqylPk9ga9MYmO79Yr+EPVaqd6bmz4MpZJ4/7LEjx03Q6azdMCPhFNY
+cYzPIDZFEj81Zj/tqA2MU/uTTUUrcXint4dHRJs34m5N68PV1Y1XhhH6FG0+X711
+ZymudoECgYEA/ChS5zmmOoLoaq2441+PzQbDP45qR6+G4slHwC8RDZhsYw0hQnp9
+n44Qagpt74J4FjxT20BdE714DZP32IqagUwatWRQ+z3UoGafkJSNc5JSEogwZ65C
+nC8RI1pPHLEvE8IzBJiqUA1kbMOMfTYW694wdN9JVZang05/AXaJzm8CgYEAwpJ8
+nJRR9JFweHRrRgnrVk0Qi+ABbN9T/nhPXYab2vjBfeBOTA1Mob0M3zMJDCnL2i+D
+K1GzE6WaYHElr45j2Wfphd/rRTk74WR4BaPpTCGaAhBQNn0ufqUkKsCPEAlTU+nG
+iyXP4OvdMPjEBckjbKm/mlX7m0njSHAY6SWNorsCgYEAi8Yubk3efwChpMC3hBIs
+vBHLmSdwclwyAPRh+X4djdO4AQ/+J8OObytond86IVHJD0pRkW+UKKUWLzCeakIq
+cxGknHgHC72yZ1d7i8FMx4uMQwmLC23lLn5ImbgtslHlLqavcRTPE6DY0hFzhtS8
+z/JSGfbLx83C/V49uKnkqbECgYA6h1oYt70XdpCAi3ShcuZp5XCuwslq+JsJlyM4
+nP9RFTcPKGQlGHMOzBGNKor0L7Z0gYpRg5f8tvoDPMX7UzfR9CIY9UyOXDMZD+HS
+wIWzMwBi0olueqV7zy1b9uSSDFwWh+IDhXJM1GaLDqnYm7KeQ0mxoV+4TLej2KSF
+rZg3dQKBgQCVrVxFV8jHBsRsH5PzMx6pUSAollmuyte9mGU1MIE7EZf+LEQIAjGZ
+9jvtAILYVJXwVZv1/zNxldUfBNuWc95ft+Gg7FEN0p0uLpdYNXQUcXuJaJ9tJ1td
+ZfvRcrUXdFNKYt9/yaGeHVaIQfp4W1faZD7OnII7EOVkUKyv/qNGAA==
+-----END RSA PRIVATE KEY-----

+ 589 - 0
examples/etc/turnserver.conf

@@ -0,0 +1,589 @@
+# Coturn TURN SERVER configuration file
+#
+# Boolean values note: where boolean value is supposed to be used,
+# you can use '0', 'off', 'no', 'false', 'f' as 'false, 
+# and you can use '1', 'on', 'yes', 'true', 't' as 'true' 
+# If the value is missed, then it means 'true'.
+#
+
+# Listener interface device (optional, Linux only).
+# NOT RECOMMENDED. 
+#
+#listening-device=eth0
+
+# TURN listener port for UDP and TCP (Default: 3478).
+# Note: actually, TLS & DTLS sessions can connect to the 
+# "plain" TCP & UDP port(s), too - if allowed by configuration.
+#
+#listening-port=3478
+
+# TURN listener port for TLS (Default: 5349).
+# Note: actually, "plain" TCP & UDP sessions can connect to the TLS & DTLS
+# port(s), too - if allowed by configuration. The TURN server 
+# "automatically" recognizes the type of traffic. Actually, two listening
+# endpoints (the "plain" one and the "tls" one) are equivalent in terms of
+# functionality; but we keep both endpoints to satisfy the RFC 5766 specs.
+# For secure TCP connections, we currently support SSL version 3 and 
+# TLS version 1.0, 1.1 and 1.2. SSL2 "encapculation mode" is also supported.
+# For secure UDP connections, we support DTLS version 1.
+#
+#tls-listening-port=5349
+
+# Alternative listening port for UDP and TCP listeners;
+# default (or zero) value means "listening port plus one". 
+# This is needed for RFC 5780 support
+# (STUN extension specs, NAT behavior discovery). The TURN Server 
+# supports RFC 5780 only if it is started with more than one 
+# listening IP address of the same family (IPv4 or IPv6).
+# RFC 5780 is supported only by UDP protocol, other protocols
+# are listening to that endpoint only for "symmetry".
+#
+#alt-listening-port=0
+							 
+# Alternative listening port for TLS and DTLS protocols.
+# Default (or zero) value means "TLS listening port plus one".
+#
+#alt-tls-listening-port=0
+	
+# Listener IP address of relay server. Multiple listeners can be specified.
+# If no IP(s) specified in the config file or in the command line options, 
+# then all IPv4 and IPv6 system IPs will be used for listening.
+#
+#listening-ip=172.17.19.101
+#listening-ip=10.207.21.238
+#listening-ip=2607:f0d0:1002:51::4
+
+# Auxiliary STUN/TURN server listening endpoint.
+# Aux servers have almost full TURN and STUN functionality.
+# The (minor) limitations are:
+#
+# 1) Auxiliary servers do not have alternative ports and
+# they do not support STUN RFC 5780 functionality (CHANGE REQUEST).
+#
+# 2) Auxiliary servers also are never returning ALTERNATIVE-SERVER reply.
+# 
+# Valid formats are 1.2.3.4:5555 for IPv4 and [1:2::3:4]:5555 for IPv6.
+#
+# There may be multiple aux-server options, each will be used for listening
+# to client requests.
+#
+#aux-server=172.17.19.110:33478
+#aux-server=[2607:f0d0:1002:51::4]:33478
+
+# (recommended for older Linuxes only)
+# Automatically balance UDP traffic over auxiliary servers (if configured).
+# The load balancing is using the ALTERNATE-SERVER mechanism.
+# The TURN client must support 300 ALTERNATE-SERVER response for this 
+# functionality.
+#
+#udp-self-balance
+
+# Relay interface device for relay sockets (optional, Linux only).
+# NOT RECOMMENDED.
+#
+#relay-device=eth1
+
+# Relay address (the local IP address that will be used to relay the 
+# packets to the peer).
+# Multiple relay addresses may be used.
+# The same IP(s) can be used as both listening IP(s) and relay IP(s).
+#
+# If no relay IP(s) specified, then the turnserver will apply the default
+# policy: it will decide itself which relay addresses to be used, and it 
+# will always be using the client socket IP address as the relay IP address
+# of the TURN session (if the requested relay address family is the same
+# as the family of the client socket).
+#
+#relay-ip=172.17.19.105
+#relay-ip=2607:f0d0:1002:51::5
+
+# For Amazon EC2 users:
+#
+# TURN Server public/private address mapping, if the server is behind NAT.
+# In that situation, if a -X is used in form "-X <ip>" then that ip will be reported
+# as relay IP address of all allocations. This scenario works only in a simple case
+# when one single relay address is be used, and no RFC5780 functionality is required.
+# That single relay address must be mapped by NAT to the 'external' IP.
+# The "external-ip" value, if not empty, is returned in XOR-RELAYED-ADDRESS field.
+# For that 'external' IP, NAT must forward ports directly (relayed port 12345
+# must be always mapped to the same 'external' port 12345).
+#
+# In more complex case when more than one IP address is involved,
+# that option must be used several times, each entry must
+# have form "-X <public-ip/private-ip>", to map all involved addresses.
+# RFC5780 NAT discovery STUN functionality will work correctly,
+# if the addresses are mapped properly, even when the TURN server itself 
+# is behind A NAT.
+#
+# By default, this value is empty, and no address mapping is used.
+#
+#external-ip=60.70.80.91
+#
+#OR:
+#
+#external-ip=60.70.80.91/172.17.19.101
+#external-ip=60.70.80.92/172.17.19.102
+
+
+# Number of relay threads to handle the established connections
+# (in addition to authentication thread and the listener thread).
+# If set to 0 then application runs relay process in a single thread,
+# in the same thread with the listener process (the authentication thread will 
+# still be a separate thread).
+#
+# In the older systems (Linux kernel before 3.9),
+# the number of UDP threads is always one thread per network listening endpoint - 
+# including the auxiliary endpoints - unless 0 (zero) or 1 (one) value is set.
+#
+#relay-threads=0
+
+# Lower and upper bounds of the UDP relay endpoints:
+# (default values are 49152 and 65535)
+#
+#min-port=49152
+#max-port=65535
+	
+# Uncomment to run TURN server in 'normal' 'moderate' verbose mode.
+# By default the verbose mode is off.
+#verbose
+	
+# Uncomment to run TURN server in 'extra' verbose mode.
+# This mode is very annoying and produces lots of output.
+# Not recommended under any normal circumstances.
+#	
+#Verbose
+
+# Uncomment to use fingerprints in the TURN messages.
+# By default the fingerprints are off.
+#
+#fingerprint
+
+# Uncomment to use long-term credential mechanism.
+# By default no credentials mechanism is used (any user allowed).
+# This option can be used with either flat file user database or 
+# PostgreSQL DB or MySQL DB or Redis DB for user keys storage.
+#
+#lt-cred-mech
+
+# Uncomment to use short-term credential mechanism.
+# By default no credentials mechanism is used (any user allowed).
+# For short-term credential mechanism you have to use PostgreSQL or 
+# MySQL or Redis database for user password storage.
+#
+#st-cred-mech
+
+# This option is opposite to lt-cred-mech or st-cred-mech. 
+# (TURN Server with no-auth option allows anonymous access).
+# If neither option is defined, and no users are defined,
+# then no-auth is default. If at least one user is defined, 
+# in this file or in command line or in usersdb file, then
+# lt-cred-mech is default.
+#
+#no-auth
+
+# TURN REST API flag.
+# Flag that sets a special authorization option that is based upon authentication secret.
+# This feature can be used with the long-term authentication mechanism, only.
+# This feature purpose is to support "TURN Server REST API", see
+# "TURN REST API" link in the project's page 
+# http://code.google.com/p/coturn/.
+#
+# This option is used with timestamp:
+# 
+# usercombo -> "timestamp:userid"
+# turn user -> usercombo
+# turn password -> base64(hmac(secret key, usercombo))
+#
+# This allows TURN credentials to be accounted for a specific user id.
+# If you don't have a suitable id, the timestamp alone can be used.
+# This option is just turning on secret-based authentication.
+# The actual value of the secret is defined either by option static-auth-secret,
+# or can be found in the turn_secret table in the database (see below).
+# 
+#use-auth-secret
+
+# 'Static' authentication secret value (a string) for TURN REST API only. 
+# If not set, then the turn server
+# will try to use the 'dynamic' value in turn_secret table
+# in user database (if present). The database-stored  value can be changed on-the-fly
+# by a separate program, so this is why that other mode is 'dynamic'.
+#
+#static-auth-secret 	
+
+# 'Static' user accounts for long term credentials mechanism, only.
+# This option cannot be used with TURN REST API or with short-term credentials
+# mechanism.
+# 'Static' user accounts are NOT dynamically checked by the turnserver process, 
+# so that they can NOT be changed while the turnserver is running.
+#
+#user=username1:key1
+#user=username2:key2
+# OR:
+#user=username1:password1
+#user=username2:password2
+#
+# Keys must be generated by turnadmin utility. The key value depends
+# on user name, realm, and password:
+#
+# Example:
+# $ turnadmin -k -u ninefingers -r north.gov -p youhavetoberealistic
+# Output: 0xbc807ee29df3c9ffa736523fb2c4e8ee
+# ('0x' in the beginning of the key is what differentiates the key from
+# password. If it has 0x then it is a key, otherwise it is a password).
+#
+# The corresponding user account entry in the config file will be:
+# 
+#user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee
+# Or, equivalently, with open clear password (less secure):
+#user=ninefingers:youhavetoberealistic
+#
+
+# 'Dynamic' user accounts database file name.
+# Only users for long-term mechanism can be stored in a flat file,
+# short-term mechanism will not work with option, the short-term
+# mechanism required PostgreSQL or MySQL or Redis database.
+# 'Dynamic' long-term user accounts are dynamically checked by the turnserver process, 
+# so that they can be changed while the turnserver is running.
+#
+# Default file name is turnuserdb.conf.
+# 
+#userdb=/usr/local/etc/turnuserdb.conf
+
+# PostgreSQL database connection string in the case that we are using PostgreSQL
+# as the user database.
+# This database can be used for long-term and short-term credential mechanisms
+# and it can store the secret value for secret-based timed authentication in TURN RESP API. 
+# See http://www.postgresql.org/docs/8.4/static/libpq-connect.html for 8.x PostgreSQL
+# versions connection string format, see 
+# http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-CONNSTRING
+# for 9.x and newer connection string formats.
+#
+#psql-userdb="host=<host> dbname=<database-name> user=<database-user> password=<database-user-password> connect_timeout=30"
+
+# MySQL database connection string in the case that we are using MySQL
+# as the user database.
+# This database can be used for long-term and short-term credential mechanisms
+# and it can store the secret value for secret-based timed authentication in TURN RESP API. 
+# Use string format as below (space separated parameters, all optional):
+#
+#mysql-userdb="host=<host> dbname=<database-name> user=<database-user> password=<database-user-password> port=<port> connect_timeout=<seconds>"
+
+# Redis database connection string in the case that we are using Redis
+# as the user database.
+# This database can be used for long-term and short-term credential mechanisms
+# and it can store the secret value for secret-based timed authentication in TURN RESP API. 
+# Use string format as below (space separated parameters, all optional):
+#
+#redis-userdb="ip=<ip-address> dbname=<database-number> password=<database-user-password> port=<port> connect_timeout=<seconds>"
+
+# Redis status and statistics database connection string, if used (default - empty, no Redis stats DB used).
+# This database keeps allocations status information, and it can be also used for publishing
+# and delivering traffic and allocation event notifications.
+# The connection string has the same parameters as redis-userdb connection string. 
+# Use string format as below (space separated parameters, all optional):
+#
+#redis-statsdb="ip=<ip-address> dbname=<database-number> password=<database-user-password> port=<port> connect_timeout=<seconds>"
+
+# The default realm to be used for the users when no explicit 
+# origin/realm relationship was found in the database, or if the TURN
+# server is not using any database (just the commands-line settings
+# and the userdb file). Must be used with long-term credentials 
+# mechanism or with TURN REST API.
+#
+#realm=mycompany.org
+
+# Per-user allocation quota.
+# default value is 0 (no quota, unlimited number of sessions per user).
+# This option can also be set through the database, for a particular realm.
+#
+#user-quota=0
+
+# Total allocation quota.
+# default value is 0 (no quota).
+# This option can also be set through the database, for a particular realm.
+#
+#total-quota=0
+
+# Max bytes-per-second bandwidth a TURN session is allowed to handle
+# (input and output network streams are treated separately). Anything above
+# that limit will be dropped or temporary suppressed (within
+# the available buffer limits).
+# This option can also be set through the database, for a particular realm.
+#
+#max-bps=0
+
+# Uncomment if no UDP client listener is desired.
+# By default UDP client listener is always started.
+#
+#no-udp
+
+# Uncomment if no TCP client listener is desired.
+# By default TCP client listener is always started.
+#
+#no-tcp
+
+# Uncomment if no TLS client listener is desired.
+# By default TLS client listener is always started.
+#
+#no-tls
+
+# Uncomment if no DTLS client listener is desired.
+# By default DTLS client listener is always started.
+#
+#no-dtls
+
+# Uncomment if no UDP relay endpoints are allowed.
+# By default UDP relay endpoints are enabled (like in RFC 5766).
+#
+#no-udp-relay
+
+# Uncomment if no TCP relay endpoints are allowed.
+# By default TCP relay endpoints are enabled (like in RFC 6062).
+#
+#no-tcp-relay
+
+# Uncomment if extra security is desired,
+# with nonce value having limited lifetime (600 secs).
+# By default, the nonce value is unique for a session,
+# but it has unlimited lifetime. With this option,
+# the nonce lifetime is limited to 600 seconds, after that 
+# the client will get 438 error and will have to re-authenticate itself.
+#
+#stale-nonce
+
+# Certificate file.
+# Use an absolute path or path relative to the 
+# configuration file.
+#
+#cert=/usr/local/etc/turn_server_cert.pem
+
+# Private key file.
+# Use an absolute path or path relative to the 
+# configuration file.
+# Use PEM file format.
+#
+#pkey=/usr/local/etc/turn_server_pkey.pem
+
+# Private key file password, if it is in encoded format.
+# This option has no default value.
+#
+#pkey-pwd=...
+
+# Allowed OpenSSL cipher list for TLS/DTLS connections.
+# Default value is "DEFAULT".
+#
+#cipher-list="DEFAULT"
+
+# CA file in OpenSSL format. 
+# Forces TURN server to verify the client SSL certificates.
+# By default it is not set: there is no default value and the client
+# certificate is not checked.
+#
+# Example:
+#CA-file=/etc/ssh/id_rsa.cert
+
+# Curve name for EC ciphers, if supported by OpenSSL library (TLS and DTLS).
+# The default value is prime256v1.
+#
+#ec-curve-name=prime256v1
+
+# Use 566 bits predefined DH TLS key. Default size of the key is 1066.
+#
+#dh566
+
+# Use 2066 bits predefined DH TLS key. Default size of the key is 1066.
+#
+#dh2066
+
+# Use custom DH TLS key, stored in PEM format in the file.
+# Flags --dh566 and --dh2066 are ignored when the DH key is taken from a file.
+#
+#dh-file=<DH-PEM-file-name>
+
+# Flag to prevent stdout log messages.
+# By default, all log messages are going to both stdout and to 
+# the configured log file. With this option everything will be 
+# going to the configured log only (unless the log file itself is stdout).
+#
+#no-stdout-log
+
+# Option to set the log file name.
+# By default, the turnserver tries to open a log file in 
+# /var/log, /var/tmp, /tmp and current directories directories
+# (which open operation succeeds first that file will be used).
+# With this option you can set the definite log file name.
+# The special names are "stdout" and "-" - they will force everything 
+# to the stdout. Also, the "syslog" name will force everything to
+# the system log (syslog).
+#
+#log-file=/var/tmp/turn.log
+
+# Option to redirect all log output into system log (syslog).
+#
+#syslog
+
+# This flag means that no log file rollover will be used, and the log file
+# name will be constructed as-is, without PID and date appendage.
+#simple-log
+
+# Option to set the "redirection" mode. The value of this option
+# will be the address of the alternate server for UDP & TCP service in form of 
+# <ip>[:<port>]. The server will send this value in the attribute
+# ALTERNATE-SERVER, with error 300, on ALLOCATE request, to the client.
+# Client will receive only values with the same address family
+# as the client network endpoint address family. 
+# See RFC 5389 and RFC 5766 for ALTERNATE-SERVER functionality description. 
+# The client must use the obtained value for subsequent TURN communications.
+# If more than one --alternate-server options are provided, then the functionality
+# can be more accurately described as "load-balancing" than a mere "redirection". 
+# If the port number is omitted, then the default port 
+# number 3478 for the UDP/TCP protocols will be used.
+# Colon (:) characters in IPv6 addresses may conflict with the syntax of 
+# the option. To alleviate this conflict, literal IPv6 addresses are enclosed 
+# in square brackets in such resource identifiers, for example: 
+# [2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478 . 
+# Multiple alternate servers can be set. They will be used in the
+# round-robin manner. All servers in the pool are considered of equal weight and 
+# the load will be distributed equally. For example, if we have 4 alternate servers, 
+# then each server will receive 25% of ALLOCATE requests. A alternate TURN server 
+# address can be used more than one time with the alternate-server option, so this 
+# can emulate "weighting" of the servers.
+#
+# Examples: 
+#alternate-server=1.2.3.4:5678
+#alternate-server=11.22.33.44:56789
+#alternate-server=5.6.7.8
+#alternate-server=[2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478
+			
+# Option to set alternative server for TLS & DTLS services in form of 
+# <ip>:<port>. If the port number is omitted, then the default port 
+# number 5349 for the TLS/DTLS protocols will be used. See the previous 
+# option for the functionality description.
+#
+# Examples: 
+#tls-alternate-server=1.2.3.4:5678
+#tls-alternate-server=11.22.33.44:56789
+#tls-alternate-server=[2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478
+
+# Option to suppress TURN functionality, only STUN requests will be processed.
+# Run as STUN server only, all TURN requests will be ignored.
+# By default, this option is NOT set.
+#
+#stun-only
+
+# Option to suppress STUN functionality, only TURN requests will be processed.
+# Run as TURN server only, all STUN requests will be ignored.
+# By default, this option is NOT set.
+#
+#no-stun
+
+# This is the timestamp/username separator symbol (character) in TURN REST API.
+# The default value is ':'.
+# rest-api-separator=:	
+
+# Flag that can be used to disallow peers on the loopback addresses (127.x.x.x and ::1).
+# This is an extra security measure.
+#
+#no-loopback-peers
+
+# Flag that can be used to disallow peers on well-known broadcast addresses (224.0.0.0 and above, and FFXX:*).
+# This is an extra security measure.
+#
+#no-multicast-peers
+
+# Option to set the max time, in seconds, allowed for full allocation establishment. 
+# Default is 60 seconds.
+#
+#max-allocate-timeout=60
+
+# Option to allow or ban specific ip addresses or ranges of ip addresses. 
+# If an ip address is specified as both allowed and denied, then the ip address is 
+# considered to be allowed. This is useful when you wish to ban a range of ip 
+# addresses, except for a few specific ips within that range.
+#
+# This can be used when you do not want users of the turn server to be able to access
+# machines reachable by the turn server, but would otherwise be unreachable from the 
+# internet (e.g. when the turn server is sitting behind a NAT)
+#
+# Examples:
+# denied-peer-ip=83.166.64.0-83.166.95.255
+# allowed-peer-ip=83.166.68.45
+
+# File name to store the pid of the process.
+# Default is /var/run/turnserver.pid (if superuser account is used) or
+# /var/tmp/turnserver.pid .
+#
+#pidfile="/var/run/turnserver.pid"
+
+# Require authentication of the STUN Binding request.
+# By default, the clients are allowed anonymous access to the STUN Binding functionality.
+#
+#secure-stun
+
+# Require SHA256 digest function to be used for the message integrity.
+# By default, the server uses SHA1 (as per TURN standard specs). 
+# With this option, the server 
+# always requires the stronger SHA256 function. The client application
+# must support SHA256 hash function if this option is used. If the server obtains 
+# a message from the client with a weaker (SHA1) hash function then the 
+# server returns error code 426.
+#
+#sha256
+
+# Mobility with ICE (MICE) specs support.
+#
+#mobility
+
+# User name to run the process. After the initialization, the turnserver process
+# will make an attempt to change the current user ID to that user.
+#
+#proc-user=<user-name>
+
+# Group name to run the process. After the initialization, the turnserver process
+# will make an attempt to change the current group ID to that group.
+#
+#proc-group=<group-name>
+
+# Turn OFF the CLI support.
+# By default it is always ON.
+# See also options cli-ip and cli-port.
+#
+#no-cli
+
+#Local system IP address to be used for CLI server endpoint. Default value
+# is 127.0.0.1.
+#
+#cli-ip=127.0.0.1
+
+# CLI server port. Default is 5766.
+#
+#cli-port=5766
+
+# CLI access password. Default is empty (no password).
+#
+#cli-password=logen
+
+# Server relay. NON-STANDARD AND DANGEROUS OPTION. 
+# Only for those applications when we want to run 
+# server applications on the relay endpoints.
+# This option eliminates the IP permissions check on 
+# the packets incoming to the relay endpoints.
+#
+#server-relay
+
+# Maximum number of output sessions in ps CLI command.
+# This value can be changed on-the-fly in CLI. The default value is 256.
+#
+#cli-max-output-sessions
+
+# Set network engine type for the process (for internal purposes).
+#
+#ne=[1|2|3]
+
+# Do not allow an SSL/TLS version of protocol
+#
+#no-sslv2
+#no-sslv3
+#no-tlsv1
+#no-tlsv1_1
+#no-tlsv1_2

+ 23 - 0
examples/etc/turnuserdb.conf

@@ -0,0 +1,23 @@
+#This file can be used as user accounts storage for long-term credentials mechanism.
+#
+#username1:key1
+#username2:key2
+# OR:
+#username1:password1
+#username2:password2
+#
+# Keys must be generated by turnadmin utility. The key value depends
+# on user name, realm, and password:
+#
+# Example:
+# $ turnadmin -k -u ninefingers -r north.gov -p youhavetoberealistic
+# Output: 0xbc807ee29df3c9ffa736523fb2c4e8ee
+# ('0x' in the beginning of the key is what differentiates the key from
+# password. If it has 0x then it is a key, otherwise it is a password).
+#
+# The corresponding user account entry in the userdb file will be:
+# 
+#ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee
+# Or, equivalently (less secure):
+#ninefingers:youhavetoberealistic
+#

+ 35 - 0
examples/scripts/basic/dos_attack.sh

@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# This is an example of a script for DOS attack emulation
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+while [ 0 ] ; do
+
+PATH=examples/bin/:../bin/:bin/:${PATH} turnutils_uclient -O -D -G -n 1 -m 12 -e 127.0.0.1 -X -g $@ ::1 &
+
+PATH=examples/bin/:../bin/:bin/:${PATH} turnutils_uclient -O -G -n 1 -m 12 -y -s $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin:bin/:${PATH} turnutils_uclient -O -G -t -n 1 -m 12 -e 127.0.0.1 -X -g $@ ::1 &
+
+PATH=examples/bin/:../bin:bin/:${PATH} turnutils_uclient -O -G -T -n 1 -m 12 -y -s $@ 127.0.0.1 &
+
+sleep 1
+
+type killall >>/dev/null 2>>/dev/null
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+  killall turnutils_uclient >>/dev/null 2>>/dev/null
+else
+  type pkill >>/dev/null 2>>/dev/null
+  ER=$?
+  if [ ${ER} -eq 0 ] ; then
+    pkill turnutils_u >>/dev/null 2>>/dev/null
+  fi
+fi
+
+done

+ 30 - 0
examples/scripts/basic/relay.sh

@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# non-secure mode (when authentication is not used).
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+# Other options:
+# set bandwidth limit on client session 3000000 bytes per second (--max-bps)
+# use fingerprints (-f)
+# use 3 relay threads (-m 3)
+# use min UDP relay port 32355 and max UDP relay port 65535
+# --no-tls and --no-dtls mean that we are not trying to
+# --no-auth means that no authentication to be used, 
+# allow anonymous users. 
+# start TLS and DTLS services.
+# Other parameters (config file name, etc) are default.
+  
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="bin:../bin:../../bin:${PATH}" turnserver -v --syslog -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 --no-tls --no-dtls --no-auth $@
+
+
+
+

+ 27 - 0
examples/scripts/basic/tcp_client.sh

@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "unsecure" TURN TCP client.
+# Options:
+# 1) -t is present, it means that TCP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 11) -X means that IPv4 relay address is requested.
+# 12) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin:bin/:${PATH} turnutils_uclient -t -n 1000 -m 10 -l 3037 -e 127.0.0.1 -g -X $@ ::1
+

+ 25 - 0
examples/scripts/basic/tcp_client_c2c_tcp_relay.sh

@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "unsecure" TURN TCP client
+# with TCP relay endpoints (RFC 6062).
+# Options:
+# 1) -T is present, it means that TCP networking is used with TCP relay endpoints.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will connect to the 'neighbor' clients, no peer app will be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin:bin/:${PATH} turnutils_uclient -T -n 1000 -m 10 -l 170 -y -g $@ ::1
+

+ 29 - 0
examples/scripts/basic/udp_c2c_client.sh

@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "unsecure" TURN UDP client,
+# in client-to-client fashion (when client talks to another client
+# through their corresponding allocated relayed endpoints).
+# Options:
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -y means "client to client" communication pattern. 
+# the client calculates the peer address
+# (which is the allocated relayed endpoint of the next client in array of clients).
+# 8) -l 170 means that the payload size of the packets is 170 bytes 
+# like average audio RTP packet).  
+# 9) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 10) 127.0.0.1 (the last parameter) is the TURN Server IP address.
+# 11) -z 5 means that we want 5 ms interval between the packets (per each session).
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:bin/:${PATH} turnutils_uclient -n 1000 -m 10 -y -l 170 -z 15 $@ 127.0.0.1
+

+ 28 - 0
examples/scripts/basic/udp_client.sh

@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "unsecure" TURN UDP client.
+# Options:
+# 0) -D means "mandatory padding", like pjnath does;
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 171 means that the payload size of the packets is 171 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 11) -X means that IPv4 relay address is requested.
+# 12) 127.0.0.1 (the last parameter) is the TURN Server IP address. We use IPv4 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:bin/:${PATH} turnutils_uclient -D -n 1000 -m 10 -l 171 -e 127.0.0.1 -g -X $@ 127.0.0.1
+

+ 38 - 0
examples/scripts/loadbalance/master_relay.sh

@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# This is an example of a MASTER TURN server that distributes
+# the load among several "slave" TURN servers.
+#
+# The TURN Server is started in
+# secure mode (when authentication is used) - see option -a
+# that means "use long-term credential mechanism".
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1. We use 127.0.0.1 as the relay address, too.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) "--user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee" means 
+# "allow user 'ninefinger' with generated key '0xbc807ee29df3c9ffa736523fb2c4e8ee' ".
+# 7) "--user=gorst:hero" means "allow user 'gorst' with password 'hero' ". 
+# 8) "--log-file=stdout" means that all log output will go to the stdout. 
+# 9) "-v" means normal verbose mode (with some moderate logging).
+# 10) --no-dtls and --no-tls measn that we are not using DTLS & TLS protocols here 
+# (for the sake of simplicity).
+# 11) --alternate-server options set the "slave" servers.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --syslog -a -L 127.0.0.1 -E 127.0.0.1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 --user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee --user=gorst:hero -r north.gov --log-file=stdout -v --no-dtls --no-tls --alternate-server=127.0.0.1:3333 --alternate-server=127.0.0.1:4444 $@
+ 

+ 37 - 0
examples/scripts/loadbalance/slave_relay_1.sh

@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# This is an example of a SLAVE TURN server that accepts
+# the redirected requests.
+#
+# The TURN Server is started in
+# secure mode (when authentication is used) - see option -a
+# that means "use long-term credential mechanism".
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1. We use 127.0.0.1 as the relay address, too.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 10000 and max UDP relay port 19999 
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) "--user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee" means 
+# "allow user 'ninefinger' with generated key '0xbc807ee29df3c9ffa736523fb2c4e8ee' ".
+# 7) "--user=gorst:hero" means "allow user 'gorst' with password 'hero' ". 
+# 8) "--log-file=stdout" means that all log output will go to the stdout. 
+# 9) "-v" means normal verbose mode (with some moderate logging).
+# 10) --no-dtls and --no-tls measn that we are not using DTLS & TLS protocols here 
+# (for the sake of simplicity).
+# 11) -p 3333 means that we are using UDP & TCP listening port 3333.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --syslog -a -L 127.0.0.1 -E 127.0.0.1 --max-bps=3000000 -f -m 3 --min-port=10000 --max-port=19999 --user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee --user=gorst:hero -r north.gov --log-file=stdout -v --no-dtls --no-tls -p 3333 --cli-port=5767 $@

+ 37 - 0
examples/scripts/loadbalance/slave_relay_2.sh

@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# This is an example of a SLAVE TURN server that accepts
+# the redirected requests.
+#
+# The TURN Server is started in
+# secure mode (when authentication is used) - see option -a
+# that means "use long-term credential mechanism".
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1. We use 127.0.0.1 as the relay address, too.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 20000 and max UDP relay port 29999 
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) "--user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee" means 
+# "allow user 'ninefinger' with generated key '0xbc807ee29df3c9ffa736523fb2c4e8ee' ".
+# 7) "--user=gorst:hero" means "allow user 'gorst' with password 'hero' ". 
+# 8) "--log-file=stdout" means that all log output will go to the stdout. 
+# 9) "-v" means normal verbose mode (with some moderate logging).
+# 10) --no-dtls and --no-tls measn that we are not using DTLS & TLS protocols here 
+# (for the sake of simplicity).
+# 11) -p 4444 means that we are using UDP & TCP listening port 4444.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --syslog -a -L 127.0.0.1 -E 127.0.0.1 --max-bps=3000000 -f -m 3 --min-port=20000 --max-port=29999 --user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee --user=gorst:hero -r north.gov --log-file=stdout -v --no-dtls --no-tls -p 4444 --cli-port=5768 $@

+ 29 - 0
examples/scripts/loadbalance/tcp_c2c_tcp_relay.sh

@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN TCP client
+# with the long-term credentials mechanism and with
+# TCP relay endpoints (RFC 6062).
+#
+# Options:
+#
+# 1) -T is present, it means that TCP networking is used, with TCP relay endpoints (RFC 6062).
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will connect to the 'neighbor' clients, no peer app will be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u gorst means that if the server challenges the client with 
+# authentication challenge, then we use account "gorst".
+# 11) -w hero sets the password for the account as "hero".
+# 12) 127.0.0.1 (the last parameter) is the TURN Server IP address.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -T -n 1000 -m 10 -l 170 -y -g -u gorst -w hero $@ 127.0.0.1

+ 31 - 0
examples/scripts/loadbalance/udp_c2c.sh

@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN UDP client
+# with the long-term credentials mechanism,
+# in client-to-client communication patter.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will be connecting to each other and the peer will not be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u ninefingers means that if the server challenges the client with 
+# authentication challenge, then we use account "ninefingers".
+# 11) -w youhavetoberealistic sets the password for the account as "youhavetoberealistic".
+# 12) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 13) 127.0.0.1 (the last parameter) is the TURN Server IP address.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -n 1000 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y $@ 127.0.0.1

+ 49 - 0
examples/scripts/longtermsecure/secure_dos_attack.sh

@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# This is an example of a script to run a DOS attack in a 
+# "secure" environment
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+while [ 0 ] ; do 
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G -O -n 10 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G -O -n 10 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G -O -S -k turn_client_pkey.pem -n 10 -m 10 -l 170 -e ::1 -x -g -u ninefingers -w youhavetoberealistic -s $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G -O -t -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G -O -T -n 10 -m 10 -l 170 -y -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G -O -T -S -k turn_client_pkey.pem -n 10 -m 10 -l 170 -y -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G -O -t -S -k turn_client_pkey.pem -n 10 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1 &
+
+sleep 2
+
+type killall >>/dev/null 2>>/dev/null
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+  killall turnutils_uclient >>/dev/null 2>>/dev/null
+fi
+
+type pkill >>/dev/null 2>>/dev/null
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+  pkill turnutils_u >>/dev/null 2>>/dev/null
+  pkill turnutils_uclie >>/dev/null 2>>/dev/null
+  pkill turnutils_uclient >>/dev/null 2>>/dev/null
+else
+  sleep 10
+fi
+
+done
+
+

+ 36 - 0
examples/scripts/longtermsecure/secure_dtls_client.sh

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN DTLS client
+# with the long-term credentials mechanism.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 2) -S means "SSL protocol with default encryption"
+# 3) -i absent.
+# 4) -k sets private key file for TLS.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer IPv4 address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u ninefingers means that if the server challenges the client with 
+# authentication challenge, then we use account "ninefingers".
+# 11) -w youhavetoberealistic sets the password for the account.
+# 12) -s option absent - that means that the client will be using 
+#     the channel mechanism for data.
+# 13) 127.0.0.1 (the last parameter) is the TURN Server IP address. 
+# We use IPv6 - to - IPv4 here to illustrate how the TURN Server 
+# converts the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -S -k turn_client_pkey.pem -n 1000 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic $@ 127.0.0.1
+

+ 36 - 0
examples/scripts/longtermsecure/secure_dtls_client_cert.sh

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN DTLS client
+# with the long-term credentials mechanism and with certificate check.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 2) -S means "SSL protocol with default encryption"
+# 3) -i sets certificate file for TLS. -R sets certificate check mode.
+#    -E sets CA file for certificate check.
+# 4) -k sets private key file for TLS.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer IPv4 address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u bolt means that if the server challenges the client with 
+# authentication challenge, then we use account "bolt".
+# 11) -w kwyjibo sets the password for the account.
+# 12) -s option means that the client will be using "send" mechanism for data.
+# 13) 127.0.0.1 (the last parameter) is the TURN Server IP address. 
+# We use IPv6 - to - IPv4 here to illustrate how the TURN Server 
+# converts the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -S -i turn_server_cert.pem -k turn_server_pkey.pem -E turn_server_cert.pem -n 1000 -m 10 -l 170 -e 127.0.0.1 -g -u bolt -w kwyjibo -s -X $@ 127.0.0.1
+

+ 35 - 0
examples/scripts/longtermsecure/secure_relay.sh

@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure mode (when authentication is used) - see option -a
+# that means "use long-term credential mechanism".
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 10 relay threads (-m 10)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) "--user=ninefingers:youhavetoberealistic" means 
+# "allow user 'ninefinger' with password 'youhavetoberealistic' ".
+# 7) "--user=gorst:hero" means "allow user 'gorst' with password 'hero' ".
+# 8) "--cert=turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 9) "--pkey=turn_server_pkey.pem" sets the OpenSSL private key name.
+# 10) "--log-file=stdout" means that all log output will go to the stdout. 
+# 11) "-v" means normal verbose mode (with some moderate logging).
+# 12) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 10 --min-port=32355 --max-port=65535 --user=ninefingers:youhavetoberealistic --user=gorst:hero -r north.gov --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout -v --cipher-list=ALL:SSLv2 $@

+ 38 - 0
examples/scripts/longtermsecure/secure_relay_cert.sh

@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure mode (when authentication is used) - see option -a
+# that means "use long-term credential mechanism".
+#
+# This script shows how to use certificate check option.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 10 relay threads (-m 10)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) "-r bolt.co" means "use authentication realm 'bolt.co'"
+# 6) "--user=ninefingers:youhavetoberealistic" means "allow user 
+#			'ninefinger' with password 'youhavetoberealistic'.".
+# 7) "--user=bolt:kwyjibo" means "allow user 'bolt' with password 'kwyjibo' ".
+# 8) "--cert=..." sets the OpenSSL certificate file name. 
+# 9) "--pkey=..." sets the OpenSSL private key name.
+# 10) --CA-file sets the CA file for client certificate check.
+# 11) "--log-file=stdout" means that all log output will go to the stdout.
+# 12) "-v" means normal verbose mode (with some moderate logging).
+# 13) --cipher-list="ALL:SSLv2:!eNULL:!aNULL:!NULL" measn "all ciphers, except anonymous".
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 10 --min-port=32355 --max-port=65535 --user=ninefingers:youhavetoberealistic --user=bolt:kwyjibo -r bolt.co --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --CA-file=turn_server_cert.pem --log-file=stdout -v --cipher-list="ALL:SSLv2:!eNULL:!aNULL:!NULL" $@

+ 31 - 0
examples/scripts/longtermsecure/secure_tcp_client.sh

@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN TCP client
+# with the long-term credentials mechanism.
+#
+# Options:
+#
+# 1) -t is present, it means that TCP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u gorst means that if the server challenges the client with 
+# authentication challenge, then we use account "gorst".
+# 11) -w hero sets the password for the account as "hero".
+# 12) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 13) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -t -n 3000 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1

+ 31 - 0
examples/scripts/longtermsecure/secure_tcp_client_c2c_tcp_relay.sh

@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN TCP client
+# with the long-term credentials mechanism and with
+# TCP relay endpoints (RFC 6062).
+#
+# Options:
+#
+# 1) -T is present, it means that TCP networking is used, with TCP relay endpoints (RFC 6062).
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will connect to the 'neighbor' clients, no peer app will be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u gorst means that if the server challenges the client with 
+# authentication challenge, then we use account "gorst".
+# 11) -w hero sets the password for the account as "hero".
+# 12) 127.0.0.1 (the last parameter) is the TURN Server IP address. We use IPv4 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -T -n 1000 -m 10 -l 170 -y -g -u gorst -w hero $@ 127.0.0.1
+

+ 34 - 0
examples/scripts/longtermsecure/secure_tls_client.sh

@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN TLS client
+# with the long-term credentials mechanism.
+#
+# Options:
+#
+# 1) -t is present, it means that TCP networking is used.
+# 2) -S means "SSL/TLS protocol with default cipher".
+# 3) -i absent.
+# 4) -k sets private key file for TLS.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u gorst means that if the server challenges the client with 
+# authentication challenge, then we use account "gorst".
+# 11) -w hero sets the password for the account as "hero".
+# 12) -s option means that the client will be using "send" mechanism for data.
+# 13) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -t -S -k turn_client_pkey.pem -n 1000 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1
+

+ 35 - 0
examples/scripts/longtermsecure/secure_tls_client_c2c_tcp_relay.sh

@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN TLS client
+# with the long-term credentials mechanism and with
+# TCP relay endpoints (RFC 6062).
+#
+# Options:
+#
+# 1) -T is present, it means that TCP networking is used,  with TCP 
+# relay endpoints (RFC 6062.
+# 2) -S means that "secure protocol", that is TLS in the case of TCP, 
+# will be used between the client and the TURN Server.
+# 3) -i absent.
+# 4) -k sets private key file for TLS.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will connect to the 'neighbor' clients, no peer app will be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u gorst means that if the server challenges the client with 
+# authentication challenge, then we use account "gorst".
+# 11) -w hero sets the password for the account as "hero".
+# 12) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/postgres/9.2-pgdg/lib
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -T -S -k turn_client_pkey.pem -n 1000 -m 10 -l 170 -y -g -u gorst -w hero $@ ::1

+ 36 - 0
examples/scripts/longtermsecure/secure_tls_client_cert.sh

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN DTLS client
+# with the long-term credentials mechanism and with certificate check.
+#
+# Options:
+#
+# 1) -t means that TCP networking is used.
+# 2) -S means "SSL protocol with default encryption"
+# 3) -i sets certificate file for TLS. -R sets certificate check mode.
+#    -E sets CA file for certificate check.
+# 4) -k sets private key file for TLS.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer IPv4 address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u bolt means that if the server challenges the client with 
+# authentication challenge, then we use account "bolt".
+# 11) -w kwyjibo sets the password for the account.
+# 12) -s option means that the client will be using "send" mechanism for data.
+# 13) 127.0.0.1 (the last parameter) is the TURN Server IP address. 
+# We use IPv6 - to - IPv4 here to illustrate how the TURN Server 
+# converts the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -t -S -i turn_server_cert.pem -k turn_server_pkey.pem -E turn_server_cert.pem -n 1000 -m 10 -l 170 -e 127.0.0.1 -X -g -u bolt -w kwyjibo -s $@ 127.0.0.1
+

+ 32 - 0
examples/scripts/longtermsecure/secure_udp_c2c.sh

@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN UDP client
+# with the long-term credentials mechanism,
+# in client-to-client communication patter.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will be connecting to each other and the peer will not be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u ninefingers means that if the server challenges the client with 
+# authentication challenge, then we use account "ninefingers".
+# 11) -w youhavetoberealistic sets the password for the account as "youhavetoberealistic".
+# 12) -s option is present - it means that the client will be using 
+# the DATA mechanism for data.
+# 13) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -s -n 1000 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y $@ ::1

+ 32 - 0
examples/scripts/longtermsecure/secure_udp_client.sh

@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN UDP client
+# with the long-term credentials mechanism.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u ninefingers means that if the server challenges the client with 
+# authentication challenge, then we use account "ninefingers".
+# 11) -w youhavetoberealistic sets the password for the account as "youhavetoberealistic".
+# 12) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 13) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -n 1000 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic $@ ::1
+

+ 34 - 0
examples/scripts/longtermsecuredb/secure_relay_with_db_mysql.sh

@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure mode with MySQL database for users 
+# with the long-term credentials mechanism.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" 
+# means that local MySQL database "coturn" will be used, with database user "turn" and 
+# database user password "turn", and connection timeout 30 seconds.
+# 7) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 8) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 9) "--log-file=stdout" means that all log output will go to the stdout.
+# 10) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@

+ 37 - 0
examples/scripts/longtermsecuredb/secure_relay_with_db_psql.sh

@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure mode with Postgres database for users
+# with the long-term credentials mechanism.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) --psql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" 
+# means that local database "coturn" will be used, with database user "turn" and database user 
+# password "turn".
+# 7) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 8) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 9) "--log-file=stdout" means that all log output will go to the stdout.
+# 10) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --psql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@ 
+
+# Newer PostgreSQL style connection string example:
+# PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --psql-userdb=postgresql://turn:turn@/turn --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@

+ 37 - 0
examples/scripts/longtermsecuredb/secure_relay_with_db_redis.sh

@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure mode with Redis database for users 
+# with the long-term credentials mechanism.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" 
+# means that local Redis database 0 will be used,  
+# database password is "turn", and connection timeout 30 seconds.
+# 7) --redis-statsdb="ip=127.0.0.1 dbname=3 password=turn connect_timeout=30"
+# means that we want to use Redis for status and statistics information,
+# and this will be the database number 3.
+# 8) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 9) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 10) "--log-file=stdout" means that all log output will go to the stdout.
+# 11) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 -r north.gov --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" --redis-statsdb="ip=127.0.0.1 dbname=3 password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@

+ 36 - 0
examples/scripts/mobile/mobile_dtls_client.sh

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN DTLS client
+# with "mobile" option and the long-term credentials mechanism.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 2) -S means "SSL protocol with default encryption"
+# 3) -i absent.
+# 4) -k sets private key file for TLS.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer IPv4 address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u ninefingers means that if the server challenges the client with 
+# authentication challenge, then we use account "ninefingers".
+# 11) -w youhavetoberealistic sets the password for the account.
+# 12) -s option means that the client will be using "send" mechanism for data.
+# 13) -M turns on the Mobile ICE TURN functionality.
+# 14) 127.0.0.1 (the last parameter) is the TURN Server IP address. 
+# We use IPv6 - to - IPv4 here to illustrate how the TURN Server 
+# converts the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -S -k turn_client_pkey.pem -n 1000 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic -s -M $@ 127.0.0.1
+

+ 36 - 0
examples/scripts/mobile/mobile_relay.sh

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# This is an example how to start a "mobile" TURN Server in
+# secure mode (when authentication is used) - see option -a
+# that means "use long-term credential mechanism".
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 10 relay threads (-m 10)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) "-r north.gov" means "use authentication realm north.gov"
+# 6) "--user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee" means 
+# "allow user 'ninefinger' with generated key '0xbc807ee29df3c9ffa736523fb2c4e8ee' ".
+# 7) "--user=gorst:hero" means "allow user 'gorst' with password 'hero' ".
+# 8) "--cert=turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 9) "--pkey=turn_server_pkey.pem" sets the OpenSSL private key name.
+# 10) "--log-file=stdout" means that all log output will go to the stdout. 
+# 11) "-v" means normal verbose mode (with some moderate logging).
+# 12) "--mobility" turns on the Mobile ICE TURN functionality.
+# 13) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 10 --min-port=32355 --max-port=65535 --user=ninefingers:0xbc807ee29df3c9ffa736523fb2c4e8ee --user=gorst:hero -r north.gov --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout -v --mobility --cipher-list=ALL:SSLv2 $@

+ 32 - 0
examples/scripts/mobile/mobile_tcp_client.sh

@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" "mobile" 
+# TURN TCP client with the long-term credentials mechanism.
+#
+# Options:
+#
+# 1) -t is present, it means that TCP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u gorst means that if the server challenges the client with 
+# authentication challenge, then we use account "gorst".
+# 11) -w hero sets the password for the account as "hero".
+# 12) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 13) -M turns on the Mobile ICE TURN functionality.
+# 14) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -t -n 3000 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -M $@ ::1

+ 36 - 0
examples/scripts/mobile/mobile_tls_client_c2c_tcp_relay.sh

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN TLS client
+# with "mobile" option and with the long-term credentials mechanism and with
+# TCP relay endpoints (RFC 6062).
+#
+# Options:
+#
+# 1) -T is present, it means that TCP networking is used,  with TCP 
+# relay endpoints (RFC 6062.
+# 2) -S means that "secure protocol", that is TLS in the case of TCP, 
+# will be used between the client and the TURN Server.
+# 3) -i absent.
+# 4) -k sets private key file for TLS.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will connect to the 'neighbor' clients, no peer app will be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u gorst means that if the server challenges the client with 
+# authentication challenge, then we use account "gorst".
+# 11) -w hero sets the password for the account as "hero".
+# 12) -M turns on the Mobile ICE TURN functionality.
+# 13) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/postgres/9.2-pgdg/lib
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -T -S -k turn_client_pkey.pem -n 1000 -m 10 -l 170 -y -g -u gorst -w hero -M $@ ::1

+ 33 - 0
examples/scripts/mobile/mobile_udp_client.sh

@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN UDP client
+# with "mobile" option and with the long-term credentials mechanism.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u ninefingers means that if the server challenges the client with 
+# authentication challenge, then we use account "ninefingers".
+# 11) -w youhavetoberealistic sets the password for the account as "youhavetoberealistic".
+# 12) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 13) -M turns on the Mobile ICE TURN functionality.
+# 14) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -n 1000 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic -M $@ ::1
+

+ 16 - 0
examples/scripts/peer.sh

@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# This is a script for the peer application,
+# for testing only purposes. It opens UDP echo-like sockets
+# on IPv4 address 127.0.0.1 and IPv6 address ::1.
+# The default port 3480 is used.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:bin/:../bin:${PATH} turnutils_peer -L 127.0.0.1 -L ::1 -L 0.0.0.0 $@

+ 26 - 0
examples/scripts/readme.txt

@@ -0,0 +1,26 @@
+This directory contains various example scripts for the TURN server 
+functionality illustration.
+
+1) peer.sh starts the "peer" application that serves as a peer for all examples.
+
+2) "basic" directory contains set of scripts which works together to demonstrate 
+very basic anynymous functionality of the TURN server. The "peer.sh" must be used, too.
+
+3) "longtermsecure" directory contains set of scripts demonstrating the long-term authentication
+mechanism (peer.sh to be used, too).
+
+4) "longtermsecuredb" shows how to start TURN server with database. The clients from the
+directory "longtermsecure" can be used with the relay scripts in the "longtermsecuredb" 
+directory. Of course, the database (PostgreSQL or MySQL) must be set for these scripts
+to work correctly. 
+
+5) "restapi" shows how to use TURN REST API.
+
+6) "shorttermsecure" shows how to use the short-term authentication mechanism. The short term
+mechanism is always used with the database.
+
+7) "loadbalance" shows how to use the simple load-balancing mechanism based upon the
+ALTERNATE-SERVER functionality.
+
+
+

+ 36 - 0
examples/scripts/restapi/secure_relay_secret.sh

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure 'static' 'secret' mode (see TURNServerRESTAPI.pdf)
+# with the long-term credentials mechanism.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) --use-auth-secret means that we are using 'secret' authentication mode.
+# 6) --static-auth-secret=logen means that we will be using 'static' secret value.
+# 7) --realm=north.gov sets realm value as "north.gov".
+# 8) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 9) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 10) "--log-file=stdout" means that all log output will go to the stdout.
+# 11) "-q 100" means that single user can create no more than 100 sessions
+# 12) "-Q 300" means that there may be no more than 300 sessions totally
+# 13) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 --use-auth-secret --static-auth-secret=logen --realm=north.gov --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout -q 100 -Q 300 --cipher-list=ALL:SSLv2 $@
+

+ 38 - 0
examples/scripts/restapi/secure_relay_secret_with_db_mysql.sh

@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure 'dynamic' 'secret' mode (see TURNServerRESTAPI.pdf)
+# with MySQL database for users information
+# with the long-term credentials mechanism.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) --use-auth-secret means that we are using 'secret' authentication mode.
+# Absense of --static-auth-secret value means that we will be taking the secret value
+# from the database ('dynamic' mode).
+# 6) --realm=north.gov sets realm value as "north.gov".
+# 7) --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" 
+# means that local MySQL database "coturn" will be used, with database user "turn" and 
+# with database user password "turn", and connection timeout 30 seconds.
+# 8) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 9) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 10) "--log-file=stdout" means that all log output will go to the stdout.
+# 11) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 --use-auth-secret --realm=north.gov --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@

+ 38 - 0
examples/scripts/restapi/secure_relay_secret_with_db_psql.sh

@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure 'dynamic' 'secret' mode (see TURNServerRESTAPI.pdf)
+# with PostgreSQL database for users information
+# with the long-term credentials mechanism.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) --use-auth-secret means that we are using 'secret' authentication mode.
+# Absense of --static-auth-secret value means that we will be taking the secret value
+# from the database ('dynamic' mode).
+# 6)--realm=north.gov sets realm value as "north.gov".
+# 7) --psql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" 
+# means that local PostgreSQL database "coturn" will be used, with database user "turn" and 
+# with database user password "turn", and connection timeout 30 seconds.
+# 8) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 9) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 10) "--log-file=stdout" means that all log output will go to the stdout.
+# 11) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 --use-auth-secret --realm=north.gov --psql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@

+ 38 - 0
examples/scripts/restapi/secure_relay_secret_with_db_redis.sh

@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure 'dynamic' 'secret' mode (see TURNServerRESTAPI.pdf)
+# with Redis database for users information
+# with the long-term credentials mechanism.
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) --use-auth-secret means that we are using 'secret' authentication mode.
+# Absense of --static-auth-secret value means that we will be taking the secret value
+# from the database ('dynamic' mode).
+# 6) --realm=north.gov sets realm value as "north.gov".
+# 7) --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" 
+# means that local Redis database 0 will be used, with database  
+# password "turn", and connection timeout 30 seconds.
+# 8) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 9) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 10) "--log-file=stdout" means that all log output will go to the stdout.
+# 11) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535 --use-auth-secret --realm=north.gov --redis-userdb="ip=127.0.0.1 dbname=2 password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --redis-statsdb="ip=127.0.0.1 dbname=3 password=turn connect_timeout=30" --cipher-list=ALL:SSLv2 $@

+ 31 - 0
examples/scripts/restapi/secure_udp_client_with_secret.sh

@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN UDP client
+# with the long-term credentials mechanism and with
+# secret-based authorization (see TURNServerRESTAPI.pdf document).
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -u ninefingers means that if the server challenges the client with 
+# authentication challenge, then we use account "ninefingers".
+# 11) -W logen  sets the secret for the secret-based authentication as "logen".
+# 12) -s option is absent - it means that the client will be using 
+# the "channel" mechanism for data.
+# 13) ::1 (the last parameter) is the TURN Server IPv6 address. 
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -z 5 -n 10000 -s -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -W logen $@ ::1

+ 105 - 0
examples/scripts/restapi/shared_secret_maintainer.pl

@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+
+#
+# This is an example of Perl script maintaining dynamic shared secret 
+# database for the REST API
+#
+
+use strict;
+use warnings;
+
+use DBI;
+use HTTP::Request::Common;
+
+my $DBNAME="turn";
+my $DBUSERNAME="turn";
+my $DBPWD="turn";
+my $DBHOST="localhost";
+
+my $webserver = 'http://example.com/';
+
+my $old_secret = "";
+my $current_secret="";
+
+my $INTERVAL=3600;
+
+my $dbh;
+
+$dbh = DBI->connect("DBI:mysql:$DBNAME;host=$DBHOST", $DBUSERNAME, $DBPWD)
+	|| die "Could not connect to database: $DBI::errstr";
+    
+$dbh->do('CREATE TABLE IF NOT EXISTS turn_secret (value varchar(512))');
+
+my $c = $dbh->do("delete from turn_secret");
+print "Deleted $c rows\n";
+    
+$dbh->disconnect();
+
+do {
+
+    $dbh = DBI->connect("DBI:mysql:$DBNAME;host=$DBHOST", $DBUSERNAME, $DBPWD)
+	|| die "Could not connect to database: $DBI::errstr";
+    
+    $dbh->do('CREATE TABLE IF NOT EXISTS turn_secret (value varchar(512))');
+
+    if(length($current_secret)) {
+	if(length($old_secret)) {
+	    remove_secret($dbh, $old_secret);
+	}
+	$old_secret=$current_secret;
+    }
+    
+    print "CURRENT SECRET TO BE (RE)GENERATED\n";
+    $current_secret = generate_secret();
+    insert_secret($dbh, $current_secret);
+    
+    $dbh->disconnect();
+
+#
+# Web server interaction example:
+# Here we can put code to submit this secret to the web server:
+#
+    my $req = POST($webserver, Content => [param => $current_secret]);
+
+    $req->method('PUT');
+
+    print $req->as_string,"\n";
+
+#
+# Alternatively, you can use this link for compute-on-demand:
+# https://github.com/alfreddatakillen/computeengineondemand
+#
+# write your code here.
+#
+
+    sleep($INTERVAL);
+
+} while(1);
+
+sub remove_secret {
+
+    my $dbh = shift;
+    my $secret=shift;
+
+    my $c = $dbh->do("delete from turn_secret where value = '$secret'");
+    print "Deleted $c rows\n";
+   
+}
+
+sub insert_secret {
+
+    my $dbh = shift;
+    my $secret=shift;
+
+    my $c = $dbh->do("insert into turn_secret values('$secret')");
+    print "Inserted $c rows\n";
+    
+}
+
+sub generate_secret {
+    my @chars = ('0'..'9', 'A'..'F');
+    my $len = 8;
+    my $string;
+    while($len--){ $string .= $chars[rand @chars] };
+    return $string;
+}

+ 14 - 0
examples/scripts/rfc5769.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# This is a script for RFC 5769 STUN protocol check.
+# It checks whether the main code was compiled correctly.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:bin/:../bin:${PATH} turnutils_rfc5769check $@

+ 130 - 0
examples/scripts/selfloadbalance/secure_dos_attack.sh

@@ -0,0 +1,130 @@
+#!/bin/sh
+#
+# This is an example of a script to run a DOS attack 
+# in a "secure" environment on a server with 
+# self-load-balancing option 
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+export SLEEP_TIME=9
+
+while [ 0 ] ; do 
+
+rm -rf /var/log/turnserver/*
+
+##########################
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -n 30 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -S -k turn_client_pkey.pem -n 10 -m 10 -l 170 -e ::1 -x -g -u ninefingers -w youhavetoberealistic -s $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -t -n 50 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -T -n 30 -m 10 -l 170 -y -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -T -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -y -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -t -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -n 30 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e ::1 -x -g -u ninefingers -w youhavetoberealistic -s -p 12345 $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -t -n 50 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -T -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -T -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -t -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -n 30 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G  -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e ::1 -x -g -u ninefingers -w youhavetoberealistic -s -p 12346 $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G -t -n 50 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -G -T -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -T -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -G  -t -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12346 $@ ::1 &
+
+###########################
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -n 30 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -S -k turn_client_pkey.pem -n 10 -m 10 -l 170 -e ::1 -x -g -u ninefingers -w youhavetoberealistic -s $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -t -n 50 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -T -n 30 -m 10 -l 170 -y -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -T -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -y -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -t -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -n 30 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e ::1 -x -g -u ninefingers -w youhavetoberealistic -s -p 12345 $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -t -n 50 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -T -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -T -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -t -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12345 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -n 30 -m 10 -l 170 -g -u ninefingers -w youhavetoberealistic -y -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G  -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u ninefingers -w youhavetoberealistic -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e ::1 -x -g -u ninefingers -w youhavetoberealistic -s -p 12346 $@ 127.0.0.1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G -t -n 50 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -O -N -R -G -T -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -T -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -y -g -u gorst -w hero -p 12346 $@ ::1 &
+
+PATH=examples/bin/:../bin:./bin/:${PATH} turnutils_uclient -O -N -R -G  -t -S -k turn_client_pkey.pem -n 30 -m 10 -l 170 -e 127.0.0.1 -X -g -u gorst -w hero -p 12346 $@ ::1 &
+
+#########################
+
+sleep ${SLEEP_TIME}
+
+type killall >>/dev/null 2>>/dev/null
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+  killall turnutils_uclient >>/dev/null 2>>/dev/null
+fi
+
+type pkill >>/dev/null 2>>/dev/null
+ER=$?
+if [ ${ER} -eq 0 ] ; then
+  pkill turnutils_u >>/dev/null 2>>/dev/null
+  pkill turnutils_uclie >>/dev/null 2>>/dev/null
+  pkill turnutils_uclient >>/dev/null 2>>/dev/null
+else
+  sleep 10
+fi
+
+done
+
+

+ 42 - 0
examples/scripts/selfloadbalance/secure_relay.sh

@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server 
+# with self-udp-balancing, in secure mode 
+# (when authentication is used) - see option -a
+# that means "use long-term credential mechanism".
+#
+# We start here a TURN Server listening on IPv4 address
+# 127.0.0.1 and on IPv6 address ::1. We use 127.0.0.1 as
+# IPv4 relay address, and we use ::1 as IPv6 relay address.
+#
+# Other options:
+#
+# 1) --aux-server=... options start two auxiliary severs on IP address 127.0.0.1
+# and ports 12345 and 12346, and two auxiliary servers on IP adress ::1
+# with the same ports.
+# 2) --self-udp-balance option forces the server to distribute the load from the 
+# main server points to the auxiliary servers through the ALTERNATE-SERVER 
+# mechanism.
+# 3) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 4) use fingerprints (-f)
+# 5) use 10 relay threads (-m 10)
+# 6) use min UDP relay port 32355 and max UDP relay port 65535
+# 7) "-r north.gov" means "use authentication realm north.gov"
+# 8) "--user=ninefingers:youhavetoberealistic" means 
+# "allow user 'ninefinger' with password 'youhavetoberealistic' ".
+# 9) "--user=gorst:hero" means "allow user 'gorst' with password 'hero' ".
+# 10) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 11) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 12) "--log-file=stdout" means that all log output will go to the stdout. 
+# 13) "-v" means normal verbose mode (with some moderate logging).
+# 14) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver --aux-server=127.0.0.1:12345 --aux-server=[::1]:12345 --aux-server=127.0.0.1:12346 --aux-server=[::1]:12346 --udp-self-balance --syslog -a -L 127.0.0.1 -L ::1 -E 127.0.0.1 -E ::1 --max-bps=3000000 -f -m 10 --min-port=32355 --max-port=65535 --user=ninefingers:youhavetoberealistic --user=gorst:hero -r north.gov --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout --cipher-list=ALL:SSLv2 $@

+ 37 - 0
examples/scripts/shorttermsecure/secure_relay_short_term_mech.sh

@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# This is an example how to start a TURN Server in
+# secure mode with short-term security mechanism - see option -A
+# that means "use short-term credential mechanism".
+#
+# The short-term credentials mechanism must be used with PostgreSQL or 
+# MySQL database only, the flat file userdb cannot be used.
+#
+# We listen on available interfaces here, and we use the "external" IPs
+# for relay endpoints allocation.
+#
+# Other options:
+#
+# 1) set bandwidth limit on client session 3000000 bytes per second (--max-bps).
+# 2) use fingerprints (-f)
+# 3) use 3 relay threads (-m 3)
+# 4) use min UDP relay port 32355 and max UDP relay port 65535
+# 5) --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" 
+# means that local MySQL database "coturn" will be used, with database user "turn" and 
+# database user password "turn", and connection timeout 30 seconds.
+# 6) "--cert=example_turn_server_cert.pem" sets the OpenSSL certificate file name. 
+# 7) "--pkey=example_turn_server_pkey.pem" sets the OpenSSL private key name.
+# 8) "--log-file=stdout" means that all log output will go to the stdout.
+# 9) -E 127.0.0.1 and -E :;1 sets the relay addresses, in this case for loopback 
+# communications only.
+# 10) --cipher-list=ALL:SSLv2 means that we support all OpenSSL ciphers, including SSLv2.
+# Other parameters (config file name, etc) are default.
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/usr/local/lib/:/usr/local/mysql/lib/
+
+PATH="./bin/:../bin/:../../bin/:${PATH}" turnserver -v --syslog -A --max-bps=3000000 -f -m 3 --min-port=32355 --max-port=65535  --mysql-userdb="host=localhost dbname=coturn user=turn password=turn connect_timeout=30" --cert=turn_server_cert.pem --pkey=turn_server_pkey.pem --log-file=stdout -E 127.0.0.1 -E ::1 --cipher-list=ALL:SSLv2 $@

+ 31 - 0
examples/scripts/shorttermsecure/secure_tcp_client_c2c_tcp_relay_short_term.sh

@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN TCP client
+# with the short-term credentials mechanism and with
+# TCP relay endpoints (RFC 6062).
+#
+# Options:
+#
+# 1) -T is present, it means that TCP networking is used, with TCP relay endpoints (RFC 6062).
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -y means that the clients will connect to the 'neighbor' clients, no peer app will be used.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -A sets the short-term credentials mechanism.
+# 11) -u gorst sets the client user name.
+# 12) -w hero sets the password for the account as "hero".
+# 13) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -T -n 1000 -m 10 -l 170 -y -g -A -u gorst -w hero $@ ::1
+

+ 30 - 0
examples/scripts/shorttermsecure/secure_udp_client_short_term.sh

@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# This is an example of a script to run a "secure" TURN UDP client
+# with short-term credential mechanism.
+#
+# Options:
+#
+# 1) -t is absent, it means that UDP networking is used.
+# 5) -n 1000 means 1000 messages per single emulated client. Messages
+# are sent with interval of 20 milliseconds, to emulate an RTP stream.
+# 6) -m 10 means that 10 clients are emulated.
+# 7) -l 170 means that the payload size of the packets is 170 bytes 
+# (like average audio RTP packet).
+# 8) -e 127.0.0.1 means that the clients will use peer address 127.0.0.1.
+# 9) -g means "set DONT_FRAGMENT parameter in TURN requests".
+# 10) -A means that the short-term credentials mechanism is used.
+# 11) -u ninefingers sets the client user name.
+# 12) -w youhavetoberealistic sets the password for the user account as "youhavetoberealistic".
+# 13) -s option means that the client will be using "send" indication for data trasfer.
+# 14) ::1 (the last parameter) is the TURN Server IP address. We use IPv6 here
+# to illustrate how the TURN Server convert the traffic from IPv6 to IPv4 and back.
+#
+
+if [ -d examples ] ; then
+       cd examples
+fi
+
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib/
+
+PATH=examples/bin/:../bin/:./bin/:${PATH} turnutils_uclient -n 1000 -m 10 -l 170 -e 127.0.0.1 -X -g -A -u ninefingers -w youhavetoberealistic -s $@ ::1

+ 15 - 0
make-man.sh

@@ -0,0 +1,15 @@
+#!/bin/sh
+
+rm -rf man/man1/*
+
+txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -B "TURN Server" README.turnserver | sed -e 's/-/\\-/g' > man/man1/turnserver.1
+
+txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -B "TURN Server" README.turnadmin | sed -e 's/-/\\-/g'> man/man1/turnadmin.1
+
+txt2man -s 1 -t TURN -I turnserver -I turnadmin -I turnutils -I turnutils_uclient -I turnutils_stunclient -I turnutils_rfc5769check -I turnutils_peer -B "TURN Server" README.turnutils | sed -e 's/-/\\-/g' > man/man1/turnutils.1
+
+cd man/man1; ln -s turnutils.1 turnutils_uclient.1;cd ../..
+cd man/man1; ln -s turnutils.1 turnutils_peer.1;cd ../..
+cd man/man1; ln -s turnutils.1 turnutils_stunclient.1;cd ../..
+cd man/man1; ln -s turnserver.1 coturn.1;cd ../..
+

+ 1 - 0
man/man1/coturn.1

@@ -0,0 +1 @@
+turnserver.1

+ 325 - 0
man/man1/turnadmin.1

@@ -0,0 +1,325 @@
+.\" Text automatically generated by txt2man
+.TH TURN 1 "20 April 2014" "" ""
+.SH GENERAL INFORMATION
+
+\fIturnadmin\fP is a TURN administration tool. This tool can be used to manage 
+the user accounts (add/remove users, generate 
+TURN keys for the users). For security reasons, we do not recommend 
+storing passwords openly. The better option is to use pre\-processed "keys" 
+which are then used for authentication. These keys are generated by \fIturnadmin\fP. 
+Turnadmin is a link to \fIturnserver\fP binary, but \fIturnadmin\fP performs different 
+functions.
+.PP
+Options note: \fIturnadmin\fP has long and short option names, for most options.
+Some options have only long form, some options have only short form. Their syntax 
+somewhat different, if an argument is required:
+.PP
+The short form must be used as this (for example):
+.PP
+.nf
+.fam C
+  $ turnadmin \-u <username> \.\.\.
+
+.fam T
+.fi
+The long form equivalent must use the "=" character:
+.PP
+.nf
+.fam C
+  $ turnadmin \-\-user=<username> \.\.\.
+
+.fam T
+.fi
+If this is a flag option (no argument required) then their usage are the same, for example:
+.PP
+.nf
+.fam C
+ $ turnadmin \-k \.\.\.
+
+.fam T
+.fi
+is equivalent to:
+.PP
+.nf
+.fam C
+ $ turnadmin \-\-key \.\.\.
+
+.fam T
+.fi
+You have always the use the \fB\-r\fP <realm> option with commands for long term credentials \- 
+because data for multiple realms can be stored in the same database.
+.PP
+=====================================
+.SS  NAME
+\fB
+\fBturnadmin \fP\- a TURN relay administration tool.
+\fB
+.SS  SYNOPSIS  
+
+$ \fIturnadmin\fP [command] [options]
+.PP
+$ \fIturnadmin\fP [ \fB\-h\fP | \fB\-\-help\fP]
+.SS  DESCRIPTION
+
+.TP
+.B
+Commands:
+.TP
+.B
+\fB\-k\fP, \fB\-\-key\fP
+Generate key for a long\-term credentials mechanism user.
+.TP
+.B
+\fB\-a\fP, \fB\-\-add\fP
+Add or update a long\-term user.
+.TP
+.B
+\fB\-A\fP, \fB\-\-add\-st\fP
+Add or update a short\-term credentials mechanism user.
+.TP
+.B
+\fB\-d\fP, \fB\-\-delete\fP
+Delete a long\-term user.
+.TP
+.B
+\fB\-D\fP, \fB\-\-delete\-st\fP
+Delete a short\-term user.
+.TP
+.B
+\fB\-l\fP, \fB\-\-list\fP
+List long\-term users in the database.
+.TP
+.B
+\fB\-L\fP, \fB\-\-list\-st\fP
+List short\-term users in the database.
+.PP
+\fB\-s\fP, \fB\-\-set\-secret\fP=<value> Add shared secret for TURN RESP API
+.TP
+.B
+\fB\-S\fP, \fB\-\-show\-secret\fP
+Show stored shared secrets for TURN REST API
+.PP
+\fB\-X\fP, \fB\-\-delete\-secret\fP=<value> Delete a shared secret.
+.RS
+.TP
+.B
+\fB\-\-delete\-all_secrets\fP
+Delete all shared secrets for REST API.
+.RE
+.TP
+.B
+\fB\-O\fP, \fB\-\-add\-origin\fP
+Add origin\-to\-realm relation.
+.TP
+.B
+\fB\-R\fP, \fB\-\-del\-origin\fP
+Delete origin\-to\-realm relation.
+.TP
+.B
+\fB\-I\fP, \fB\-\-list\-origins\fP
+List origin\-to\-realm relations.
+.TP
+.B
+\fB\-g\fP, \fB\-\-set\-realm\-option\fP
+Set realm params: max\-bps, total\-quota, user\-quota.
+.TP
+.B
+\fB\-G\fP, \fB\-\-list\-realm\-options\fP
+List realm params.
+.PP
+NOTE: if you are using the flat file for the user database, then you will have 
+to use a text editor to set or show the shared secrets.
+.PP
+NOTE: the origin functionality is not supported with flat user db file, 
+a "real" database must be used.
+.TP
+.B
+Options with required values:
+.TP
+.B
+\fB\-b\fP, \fB\-\-userdb\fP
+File\-based user database file name (default \- turnuserdb.conf).
+See the \fB\-\-userdb\fP option in the \fIturnserver\fP section.
+.TP
+.B
+\fB\-e\fP, \fB\-\-psql\-userdb\fP
+PostgreSQL user database connection string.
+See the \fB\-\-psql\-userdb\fP option in the \fIturnserver\fP section.
+.TP
+.B
+\fB\-M\fP, \fB\-\-mysql\-userdb\fP
+MySQL user database connection string.
+See the \fB\-\-mysql\-userdb\fP option in the \fIturnserver\fP section.
+.TP
+.B
+\fB\-N\fP, \fB\-\-redis\-userdb\fP
+Redis user database connection string.
+See the \fB\-\-redis\-userdb\fP option in the \fIturnserver\fP section.
+.TP
+.B
+\fB\-u\fP, \fB\-\-user\fP
+User name.
+.TP
+.B
+\fB\-r\fP, \fB\-\-realm\fP
+Realm, for long\-term credentials mechanism only.
+.TP
+.B
+\fB\-p\fP, \fB\-\-password\fP
+Password.
+.TP
+.B
+\fB\-o\fP, \fB\-\-origin\fP
+Origin
+.TP
+.B
+\fB\-H\fP, \fB\-\-sha256\fP
+Use SHA256 as the keys hash function (a non\-standard feature). 
+By default, MD5 is used for the key storage encryption 
+(as required by the current STUN/TURNstandards).
+.TP
+.B
+\fB\-\-max\-bps\fP
+Set value of realm's max\-bps parameter.
+.TP
+.B
+\fB\-\-total\-quota\fP
+Set value of realm's total\-quota parameter.
+.TP
+.B
+\fB\-\-user\-quota\fP
+Set value of realm's user\-quota parameter. 
+.TP
+.B
+\fB\-h\fP, \fB\-\-help\fP
+Help.
+.TP
+.B
+Generate a key:
+.PP
+$ \fIturnadmin\fP \fB\-k\fP \fB\-u\fP <username> \fB\-r\fP <realm> \fB\-p\fP <password>
+.PP
+Add/update a user in the userdb file or in the database:
+.PP
+$ \fIturnadmin\fP \fB\-a\fP [\fB\-b\fP <userdb\-file> | \fB\-e\fP <db\-connection\-string> | \fB\-M\fP <db\-connection\-string> | \fB\-N\fP <db\-connection\-string> ] \fB\-u\fP <username> \fB\-r\fP <realm> \fB\-p\fP <password>
+.PP
+Delete a user from the userdb file or from the database:
+.PP
+$ \fIturnadmin\fP \fB\-d\fP [\fB\-b\fP <userdb\-file> | \fB\-e\fP <db\-connection\-string> | \fB\-M\fP <db\-connection\-string> | \fB\-N\fP <db\-connection\-string> ] \fB\-u\fP <username> \fB\-r\fP <realm>
+.PP
+List all long\-term users in MySQL database:
+.PP
+$ \fIturnadmin\fP \fB\-l\fP \fB\-\-mysql\-userdb\fP="<db\-connection\-string>" \fB\-r\fP <realm>
+.PP
+List all short\-term users in Redis database:
+.PP
+$ \fIturnadmin\fP \fB\-L\fP \fB\-\-redis\-userdb\fP="<db\-connection\-string>"
+.PP
+Set secret in MySQL database:
+.PP
+$ \fIturnadmin\fP \fB\-s\fP <secret> \fB\-\-mysql\-userdb\fP="<db\-connection\-string>" \fB\-r\fP <realm>
+.PP
+Show secret stored in PostgreSQL database:
+.PP
+$ \fIturnadmin\fP \fB\-S\fP \fB\-\-psql\-userdb\fP="<db\-connection\-string>" \fB\-r\fP <realm>
+.PP
+Set origin\-to\-realm relation in MySQL database:
+.PP
+$ \fIturnadmin\fP \fB\-\-mysql\-userdb\fP="<db\-connection\-string>" \fB\-r\fP <realm> \fB\-o\fP <origin>
+.PP
+Delete origin\-to\-realm relation from Redis DB:
+.PP
+$ \fIturnadmin\fP \fB\-\-redis\-userdb\fP="<db\-connection\-string>" \fB\-o\fP <origin>
+.PP
+List all origin\-to\-realm relations in Redis DB:
+.PP
+$ \fIturnadmin\fP \fB\-\-redis\-userdb\fP="<db\-connection\-string>" \fB\-I\fP
+.PP
+List the origin\-to\-realm relations in PostgreSQL DB for a single realm:
+.PP
+$ \fIturnadmin\fP \fB\-\-psql\-userdb\fP="<db\-connection\-string>" \fB\-I\fP \fB\-r\fP <realm>
+.TP
+.B
+Help:
+.PP
+$ \fIturnadmin\fP \fB\-h\fP
+.PP
+=======================================
+.SS  DOCS
+
+After installation, run the command:
+.PP
+$ man \fIturnadmin\fP
+.PP
+or in the project root directory:
+.PP
+$ man \fB\-M\fP man \fIturnadmin\fP
+.PP
+to see the man page.
+.PP
+=====================================
+.SS  FILES
+
+/etc/turnserver.conf
+.PP
+/etc/turnuserdb.conf
+.PP
+/usr/local/etc/turnserver.conf
+.PP
+/usr/local/etc/turnuserdb.conf
+.PP
+=====================================
+.SS  DIRECTORIES
+
+/usr/local/share/\fIturnserver\fP
+.PP
+/usr/local/share/doc/\fIturnserver\fP
+.PP
+/usr/local/share/examples/\fIturnserver\fP
+.PP
+======================================
+.SS  SEE ALSO
+
+\fIturnserver\fP, \fIturnutils\fP
+.RE
+.PP
+======================================
+.SS  WEB RESOURCES
+
+project page:
+.PP
+http://code.google.com/p/coturn/
+.PP
+Wiki page:
+.PP
+http://code.google.com/p/coturn/wiki/Readme
+.PP
+forum:
+.PP
+https://groups.google.com/forum/?fromgroups=#!forum/turn\-server\-project\-rfc5766\-turn\-server/
+.RE
+.PP
+======================================
+.SS  AUTHORS
+
+Oleg Moskalenko <[email protected]>
+.PP
+Gabor Kovesdan http://kovesdan.org/
+.PP
+Daniel Pocock http://danielpocock.com/
+.PP
+John Selbie ([email protected])
+.PP
+Lee Sylvester <[email protected]>
+.PP
+Erik Johnston <[email protected]>
+.PP
+Roman Lisagor <[email protected]>
+.PP
+Vladimir Tsanev <[email protected]>
+.PP
+Po\-sheng Lin <[email protected]>
+.PP
+Peter Dunkley <[email protected]>
+.PP
+Mutsutoshi Yoshimoto <[email protected]>

+ 1121 - 0
man/man1/turnserver.1

@@ -0,0 +1,1121 @@
+.\" Text automatically generated by txt2man
+.TH TURN 1 "20 April 2014" "" ""
+.SH GENERAL INFORMATION
+
+The \fBTURN Server\fP project contains the source code of a TURN server and TURN client 
+messaging library. Also, some extra programs provided, for testing\-only 
+purposes. 
+.PP
+See the INSTALL file for the building instructions.
+.PP
+After the build, you will have the following binary images:
+.TP
+.B
+1.
+\fIturnserver\fP: \fBTURN Server\fP relay. 
+The compiled binary image of the \fBTURN Server\fP program is located in bin/ sub\-directory.
+.TP
+.B
+2.
+\fIturnadmin\fP: TURN administration tool. See README.turnadmin and \fIturnadmin\fP man page.
+.TP
+.B
+3.
+turnutils_uclient. See README.turnutils and \fIturnutils\fP man page.
+.TP
+.B
+4.
+turnutils_peer. See README.turnutils and \fIturnutils\fP man page.
+.TP
+.B
+5.
+turnutils_stunclient. See README.turnutils and \fIturnutils\fP man page.
+.TP
+.B
+6.
+turnutils_rfc5769check. See README.turnutils and \fIturnutils\fP man page.
+.PP
+In the "examples/scripts" sub\-directory, you will find the examples of command lines to be used 
+to run the programs. The scripts are meant to be run from examples/ sub\-directory, for example:
+.PP
+$ cd examples
+$ ./scripts/secure_relay.sh
+.SH RUNNING THE TURN SERVER
+
+Options note: \fIturnserver\fP has long and short option names, for most options.
+Some options have only long form, some options have only short form. Their syntax 
+somewhat different, if an argument is required:
+.PP
+The short form must be used as this (for example):
+.PP
+.nf
+.fam C
+  $ turnserver \-L 12.34.56.78
+
+.fam T
+.fi
+The long form equivalent must use the "=" character:
+.PP
+.nf
+.fam C
+  $ turnserver \-\-listening\-ip=12.34.56.78
+
+.fam T
+.fi
+If this is a flag option (no argument required) then their usage are the same, for example:
+.PP
+.nf
+.fam C
+ $ turnserver \-a
+
+.fam T
+.fi
+is equivalent to:
+.PP
+.nf
+.fam C
+ $ turnserver \-\-lt\-cred\-mech
+
+.fam T
+.fi
+=====================================
+.SS  NAME
+\fB
+\fBturnserver \fP\- a TURN relay server implementation.
+\fB
+.SS  SYNOPSIS
+.nf
+.fam C
+
+$ \fIturnserver\fP [\fB\-n\fP | \fB\-c\fP <config\-file> ] [\fIflags\fP] [ \fB\-\-userdb\fP=<userdb\-file> | \fB\-\-psql\-userdb\fP=<db\-conn\-string> | \fB\-\-mysql\-userdb\fP=<db\-conn\-string>  | \fB\-\-redis\-userdb\fP=<db\-conn\-string> ] [\fB\-z\fP | \fB\-\-no\-auth\fP | \fB\-a\fP | \fB\-\-lt\-cred\-mech\fP ] [\fIoptions\fP]
+$ \fIturnserver\fP \fB\-h\fP
+
+.fam T
+.fi
+.fam T
+.fi
+.SS  DESCRIPTION                                           
+
+.TP
+.B
+Config file settings:
+.TP
+.B
+\fB\-n\fP
+Do not use configuration file, use only command line parameters.
+.TP
+.B
+\fB\-c\fP
+Configuration file name (default \- turnserver.conf).
+The format of config file can be seen in
+the supplied examples/etc/turnserver.conf example file. Long 
+names of the \fIoptions\fP are used as the configuration 
+items names in the file. If not an absolute path is supplied, 
+then the file is searched in the following directories: 
+.RS
+.IP \(bu 3
+current directory
+.IP \(bu 3
+current directory etc/ sub\-directory
+.IP \(bu 3
+upper directory level etc/
+.IP \(bu 3
+/etc/
+.IP \(bu 3
+/usr/local/etc/
+.IP \(bu 3
+installation directory /etc
+.RE
+.TP
+.B
+User database settings:
+.TP
+.B
+\fB\-b\fP, \fB\-\-userdb\fP
+User database file name (default \- turnuserdb.conf),
+for long\-term credentials mechanism only.
+This user file database is being dynamically checked while the \fIturnserver\fP 
+is working, and the user accounts can be changed dynamically by
+editing the database.
+.TP
+.B
+\fB\-e\fP, \fB\-\-psql\-userdb\fP
+User database connection string for PostgreSQL.
+This database can be used for long\-term and short\-term credentials mechanisms,
+and it can store the secret value for secret\-based timed authentication in TURN RESP API.
+The connection string format is like that:
+.RS
+.PP
+"host=<host> dbname=<dbname> user=<db\-user> password=<db\-user\-password> connect_timeout=<seconds>" 
+(for 8.x or newer Postgres).
+.PP
+Or:
+.PP
+"postgresql://username:password@hostname:port/databasename" (for 9.x or newer Postgres). 
+See the INSTALL file for more explanations and examples.
+.PP
+Also, see http://www.PostgreSQL.org for full PostgreSQL documentation.
+.RE
+.TP
+.B
+\fB\-M\fP, \fB\-\-mysql\-userdb\fP
+User database connection string for MySQL or MariaDB. 
+This database can be used for long\-term and short\-term credentials mechanisms,
+and it can store the secret value for secret\-based timed authentication in TURN RESP API.
+The connection string format is like that:
+.RS
+.PP
+"host=<host> dbname=<dbname> user=<db\-user> password=<db\-user\-password> connect_timeout=<seconds>"
+See the INSTALL file for more explanations and examples.
+.PP
+Also, see http://www.mysql.org or http://mariadb.org 
+for full MySQL documentation.
+.RE
+.TP
+.B
+\fB\-N\fP, \fB\-\-redis\-userdb\fP
+User database connection string for Redis. 
+This database can be used for long\-term and short\-term credentials mechanisms,
+and it can store the secret value for secret\-based timed authentication in TURN RESP API.
+The connection string format is like that:
+.RS
+.PP
+"ip=<ip\-addr> dbname=<db\-number> password=<db\-password> connect_timeout=<seconds>"
+See the INSTALL file for more explanations and examples.
+.PP
+Also, see http://redis.io for full Redis documentation.
+.RE
+.TP
+.B
+Flags:
+.TP
+.B
+\fB\-v\fP, \fB\-\-verbose\fP
+Moderate verbose mode.
+.TP
+.B
+\fB\-V\fP, \fB\-\-Verbose\fP
+Extra verbose mode, very annoying and not recommended.
+.TP
+.B
+\fB\-o\fP, \fB\-\-daemon\fP
+Run server as daemon.
+.TP
+.B
+\fB\-f\fP, \fB\-\-fingerprint\fP
+Use fingerprints in the TURN messages. If an incoming request
+contains a fingerprint, then TURN server will always add 
+fingerprints to the messages in this session, regardless of the
+per\-server setting.
+.TP
+.B
+\fB\-a\fP, \fB\-\-lt\-cred\-mech\fP
+Use long\-term credentials mechanism (this one you need for WebRTC usage). 
+This option can be used with either flat file user database or 
+PostgreSQL DB or MySQL DB or Redis for user keys storage.
+.TP
+.B
+\fB\-A\fP, \fB\-\-st\-cred\-mech\fP
+Use the short\-term credentials mechanism. This option requires
+a PostgreSQL or MySQL or Redis DB for short term passwords storage.
+.TP
+.B
+\fB\-z\fP, \fB\-\-no\-auth\fP
+Do not use any credentials mechanism, allow anonymous access. 
+Opposite to \fB\-a\fP and \fB\-A\fP \fIoptions\fP. This is default option when no 
+authentication\-related \fIoptions\fP are set.
+By default, no credential mechanism is used \-
+any user is allowed.
+.TP
+.B
+\fB\-\-use\-auth\-secret\fP
+TURN REST API flag.
+Flag that sets a special WebRTC authorization option 
+that is based upon authentication secret. The feature purpose 
+is to support "\fBTURN Server\fP REST API" as described in
+the TURN REST API section below.
+This option uses timestamp as part of combined username:
+usercombo \-> "timestamp:username",
+turn user \-> usercombo,
+turn password \-> \fBbase64\fP(hmac(secret key, usercombo)).
+This allows TURN credentials to be accounted for a specific user id.
+If you don't have a suitable id, the timestamp alone can be used.
+This option is just turns on secret\-based authentication.
+The actual value of the secret is defined either by option static\-auth\-secret,
+or can be found in the turn_secret table in the database.
+This option can be used with long\-term credentials mechanisms only \-
+it does not make much sense with the short\-term mechanism.
+.TP
+.B
+\fB\-\-dh566\fP
+Use 566 bits predefined DH TLS key. Default size of the key is 1066.
+.TP
+.B
+\fB\-\-dh2066\fP
+Use 2066 bits predefined DH TLS key. Default size of the key is 1066.
+.TP
+.B
+\fB\-\-no\-sslv2\fP
+Do not allow SSLv2 protocol.
+.TP
+.B
+\fB\-\-no\-sslv3\fP
+Do not allow SSLv3 protocol.
+.TP
+.B
+\fB\-\-no\-tlsv1\fP
+Do not allow TLSv1 protocol.
+.TP
+.B
+\fB\-\-no\-tlsv1_1\fP
+Do not allow TLSv1.1 protocol.
+.TP
+.B
+\fB\-\-no\-tlsv1_2\fP
+Do not allow TLSv1.2 protocol.
+.TP
+.B
+\fB\-\-no\-udp\fP
+Do not start UDP client listeners.
+.TP
+.B
+\fB\-\-no\-tcp\fP
+Do not start TCP client listeners.
+.TP
+.B
+\fB\-\-no\-tls\fP
+Do not start TLS client listeners.
+.TP
+.B
+\fB\-\-no\-dtls\fP
+Do not start DTLS client listeners.
+.TP
+.B
+\fB\-\-no\-udp\-relay\fP
+Do not allow UDP relay endpoints defined in RFC 5766, 
+use only TCP relay endpoints as defined in RFC 6062.
+.TP
+.B
+\fB\-\-no\-tcp\-relay\fP
+Do not allow TCP relay endpoints defined in RFC 6062, 
+use only UDP relay endpoints as defined in RFC 5766. 
+.TP
+.B
+\fB\-\-stale\-nonce\fP
+Use extra security with nonce value having limited lifetime (600 secs). 
+.TP
+.B
+\fB\-\-no\-stdout\-log\fP
+Flag to prevent stdout log messages.
+By default, all log messages are going to both stdout and to
+the configured log file. With this option everything will be going to 
+the log file only (unless the log file itself is stdout).
+.TP
+.B
+\fB\-\-syslog\fP
+With this flag, all log will be redirected to the system log (syslog).
+.TP
+.B
+\fB\-\-simple\-log\fP
+This flag means that no log file rollover will be used, and the log file
+name will be constructed as\-is, without PID and date appendage.
+.TP
+.B
+\fB\-\-secure\-stun\fP
+Require authentication of the STUN Binding request.
+By default, the clients are allowed anonymous access to the STUN Binding functionality.
+.TP
+.B
+\fB\-S\fP, \fB\-\-stun\-only\fP
+Run as STUN server only, all TURN requests will be ignored. 
+Option to suppress TURN functionality, only STUN requests will be processed.
+.TP
+.B
+\fB\-\-no\-stun\fP
+Run as TURN server only, all STUN requests will be ignored. 
+Option to suppress STUN functionality, only TURN requests will be processed.
+.TP
+.B
+\fB\-\-no\-loopback\-peers\fP
+Disallow peers on the loopback addresses (127.x.x.x and ::1).
+.TP
+.B
+\fB\-\-no\-multicast\-peers\fP
+Disallow peers on well\-known broadcast addresses 
+(224.0.0.0 and above, and FFXX:*).
+.TP
+.B
+\fB\-\-sha256\fP
+Require SHA256 digest function to be used for the message integrity.
+By default, the server uses SHA1 hashes. With this option, the server 
+requires the stronger SHA256 hashes. The client application must support
+SHA256 hash function if this option is used. If the server obtains a message 
+from the client with a weaker (SHA1) hash function then the server returns 
+error code 426.
+.TP
+.B
+\fB\-\-mobility\fP
+Mobility with ICE (MICE) specs support.
+.TP
+.B
+\fB\-\-no\-cli\fP
+Turn OFF the CLI support. By default it is always ON.
+See also \fIoptions\fP \fB\-\-cli\-ip\fP and \fB\-\-cli\-port\fP.
+.TP
+.B
+\fB\-\-server\-relay\fP
+Server relay. NON\-STANDARD AND DANGEROUS OPTION. 
+Only for those applications when we want to run 
+server applications on the relay endpoints.
+This option eliminates the IP permissions check 
+on the packets incoming to the relay endpoints.
+See http://tools.ietf.org/search/rfc5766#section\-17.2.3 .
+.TP
+.B
+\fB\-\-udp\-self\-balance\fP
+(recommended for older Linuxes only)
+Automatically balance UDP traffic over auxiliary servers
+(if configured). The load balancing is using the 
+ALTERNATE\-SERVER mechanism. The TURN client must support 
+300 ALTERNATE\-SERVER response for this functionality.
+.TP
+.B
+\fB\-h\fP
+Help.
+.TP
+.B
+Options with required values:
+.TP
+.B
+\fB\-d\fP, \fB\-\-listening\-device\fP
+Listener interface device.
+(NOT RECOMMENDED. Optional functionality, Linux only). 
+The \fIturnserver\fP process must have root privileges to bind the 
+listening endpoint to a device. If \fIturnserver\fP must run as a 
+process without root privileges, then just do not use this setting.
+.TP
+.B
+\fB\-L\fP, \fB\-\-listening\-ip\fP
+Listener IP address of relay server. 
+Multiple listeners can be specified, for example:
+\fB\-L\fP ip1 \fB\-L\fP ip2 \fB\-L\fP ip3
+If no \fBIP\fP(s) specified, then all IPv4 and 
+IPv6 system IPs will be used for listening.
+The same \fBip\fP(s) can be used as both listening and relay \fBip\fP(s).
+.TP
+.B
+\fB\-p\fP, \fB\-\-listening\-port\fP
+TURN listener port for UDP and TCP listeners (Default: 3478).
+Note: actually, TLS & DTLS sessions can connect to the "plain" TCP & UDP
+\fBport\fP(s), too \- if allowed by configuration.
+.TP
+.B
+\fB\-\-tls\-listening\-port\fP
+TURN listener port for TLS and DTLS listeners (Default: 5349).
+Note: actually, "plain" TCP & UDP sessions can connect to the TLS & DTLS
+\fBport\fP(s), too \- if allowed by configuration. The TURN server 
+"automatically" recognizes the type of traffic. Actually, two listening
+endpoints (the "plain" one and the "tls" one) are equivalent in terms of
+functionality; but we keep both endpoints to satisfy the RFC 5766 specs.
+For secure TCP connections, we currently support SSL version 3 and 
+TLS versions 1.0, 1.1, 1.2. SSL2 "encapsulation mode" is also supported.
+For secure UDP connections, we support DTLS version 1.
+.TP
+.B
+\fB\-\-alt\-listening\-port\fP
+Alternative listening port for UDP and TCP listeners;
+default (or zero) value means "listening port plus one".
+This is needed for STUN CHANGE_REQUEST \- in RFC 5780 sense
+or in old RFC 3489 sense \- for NAT behavior discovery). The \fBTURN Server\fP
+supports CHANGE_REQUEST only if it is started with more than one
+listening IP address of the same family (IPv4 or IPv6). The CHANGE_REQUEST
+is only supported by UDP protocol, other protocols are listening
+on that endpoint only for "symmetry".
+.TP
+.B
+\fB\-\-alt\-tls\-listening\-port\fP
+Alternative listening port for TLS and DTLS protocols.
+Default (or zero) value means "TLS listening port plus one".
+.TP
+.B
+\fB\-\-aux\-server\fP
+Auxiliary STUN/TURN server listening endpoint.
+Aux servers have almost full TURN and STUN functionality.
+The (minor) limitations are:
+.RS
+.IP 1) 4
+Auxiliary servers do not have alternative ports and
+they do not support STUN RFC 5780 functionality (CHANGE REQUEST).
+.IP 2) 4
+Auxiliary servers also are never returning ALTERNATIVE\-SERVER reply.
+.RE
+.PP
+Valid formats are 1.2.3.4:5555 for IPv4 and [1:2::3:4]:5555 for IPv6.
+There may be multiple aux\-server \fIoptions\fP, each will be used for listening
+to client requests.
+.TP
+.B
+\fB\-i\fP, \fB\-\-relay\-device\fP
+Relay interface device for relay sockets 
+(NOT RECOMMENDED. Optional, Linux only).
+.TP
+.B
+\fB\-E\fP, \fB\-\-relay\-ip\fP
+Relay address (the local IP address that 
+will be used to relay the packets to the 
+peer). Multiple relay addresses may be used:
+\fB\-E\fP ip1 \fB\-E\fP ip2 \fB\-E\fP ip3
+The same \fBIP\fP(s) can be used as both listening \fBIP\fP(s) and relay \fBIP\fP(s).
+If no relay \fBIP\fP(s) specified, then the \fIturnserver\fP will apply the 
+default policy: it will decide itself which relay addresses to be 
+used, and it will always be using the client socket IP address as 
+the relay IP address of the TURN session (if the requested relay 
+address family is the same as the family of the client socket).
+.TP
+.B
+\fB\-X\fP, \fB\-\-external\-ip\fP
+\fBTURN Server\fP public/private address mapping, if the server is behind NAT.
+In that situation, if a \fB\-X\fP is used in form "\fB\-X\fP <ip>" then that ip will be reported
+as relay IP address of all allocations. This scenario works only in a simple case
+when one single relay address is be used, and no CHANGE_REQUEST functionality is 
+required. That single relay address must be mapped by NAT to the 'external' IP.
+The "external\-ip" value, if not empty, is returned in XOR\-RELAYED\-ADDRESS field.
+For that 'external' IP, NAT must forward ports directly (relayed port 12345
+must be always mapped to the same 'external' port 12345).
+In more complex case when more than one IP address is involved,
+that option must be used several times, each entry must
+have form "\fB\-X\fP <public\-ip/private\-ip>", to map all involved addresses.
+CHANGE_REQUEST (RFC5780 or RFC3489) NAT discovery STUN functionality will work 
+correctly, if the addresses are mapped properly, even when the TURN server itself 
+is behind A NAT.
+By default, this value is empty, and no address mapping is used.
+.TP
+.B
+\fB\-m\fP, \fB\-\-relay\-threads\fP
+Number of relay threads to handle the established connections
+(in addition to authentication thread and the listener thread).
+If set to 0 then application runs relay process in a single thread,
+in the same thread with the listener process (the authentication thread will 
+still be a separate thread). In older systems (before Linux kernel 3.9),
+the number of UDP threads is always one threads per network listening endpoint \-
+unless "\fB\-m\fP 0" or "\fB\-m\fP 1" is set.
+.TP
+.B
+\fB\-\-min\-port\fP
+Lower bound of the UDP port range for relay 
+endpoints allocation.
+Default value is 49152, according to RFC 5766.
+.TP
+.B
+\fB\-\-max\-port\fP
+Upper bound of the UDP port range for relay 
+endpoints allocation.
+Default value is 65535, according to RFC 5766.
+.TP
+.B
+\fB\-u\fP, \fB\-\-user\fP
+Long\-term security mechanism credentials user account, 
+in the column\-separated form username:key. 
+Multiple user accounts may used in the command line.
+The key is either the user password, or
+the key is generated
+by \fIturnadmin\fP command. In the second case,
+the key must be prepended with 0x symbols.
+The key is calculated over the user name, 
+the user realm, and the user password.
+This setting may not be used with TURN REST API or
+with short\-term credentials mechanism.
+.TP
+.B
+\fB\-r\fP, \fB\-\-realm\fP
+The default realm to be used for the users when no explicit 
+origin/realm relationship was found in the database, or if the TURN
+server is not using any database (just the commands\-line settings
+and the userdb file). Must be used with long\-term credentials 
+mechanism or with TURN REST API.
+.TP
+.B
+\fB\-C\fP, \fB\-\-rest\-api\-separator\fP
+This is the timestamp/username separator symbol (character) in TURN REST API.
+The default value is :.
+.TP
+.B
+\fB\-q\fP, \fB\-\-user\-quota\fP
+Per\-user allocations quota: how many concurrent 
+allocations a user can create. This option can also be set 
+through the database, for a particular realm.
+.TP
+.B
+\fB\-Q\fP, \fB\-\-total\-quota\fP
+Total allocations quota: global limit on concurrent allocations.
+This option can also be set through the database, for a particular realm.
+.TP
+.B
+\fB\-s\fP, \fB\-\-max\-bps\fP
+Max bytes\-per\-second bandwidth a TURN session is allowed to handle
+(input and output network streams are treated separately). Anything above 
+that limit will be dropped or temporary suppressed (within the
+available buffer limits). This option can also be set through the 
+database, for a particular realm.
+.TP
+.B
+\fB\-\-static\-auth\-secret\fP
+Static authentication secret value (a string) for TURN REST API only.
+If not set, then the turn server will try to use the dynamic value 
+in turn_secret table in user database (if present). The database\-stored
+value can be changed on\-the\-fly by a separate program, so this is why
+that other mode is dynamic. Multiple shared secrets can be used
+(both in the database and in the "static" fashion).
+.TP
+.B
+\fB\-\-cert\fP
+Certificate file, PEM format. Same file 
+search rules applied as for the configuration 
+file. If both \fB\-\-no\-tls\fP and \fB\-\-no\-dtls\fP \fIoptions\fP 
+are specified, then this parameter is not needed.
+Default value is turn_server_cert.pem.
+.TP
+.B
+\fB\-\-pkey\fP
+Private key file, PEM format. Same file 
+search rules applied as for the configuration 
+file. If both \fB\-\-no\-tls\fP and \fB\-\-no\-dtls\fP \fIoptions\fP 
+are specified, then this parameter is not needed.
+Default value is turn_server_pkey.pem.
+.TP
+.B
+\fB\-\-pkey\-pwd\fP
+If the private key file is encrypted, then this password to be used.
+.TP
+.B
+\fB\-\-cipher\-list\fP
+Allowed OpenSSL cipher list for TLS/DTLS connections.
+Default value is "DEFAULT".
+.TP
+.B
+\fB\-\-CA\-file\fP
+CA file in OpenSSL format. 
+Forces TURN server to verify the client SSL certificates.
+By default, no CA is set and no client certificate check is performed.
+.TP
+.B
+\fB\-\-ec\-curve\-name\fP
+Curve name for EC ciphers, if supported by OpenSSL library (TLS and DTLS).
+The default value is prime256v1.
+.TP
+.B
+\fB\-\-dh\-file\fP
+Use custom DH TLS key, stored in PEM format in the file.
+Flags \fB\-\-dh566\fP and \fB\-\-dh2066\fP are ignored when the DH key is taken from a file.
+.TP
+.B
+\fB\-l\fP, \fB\-\-log\-file\fP
+Option to set the full path name of the log file.
+By default, the \fIturnserver\fP tries to open a log file in 
+/var/log/\fIturnserver\fP, /var/log, /var/tmp, /tmp and . (current) 
+directories (which file open operation succeeds 
+first that file will be used). With this option you can set the 
+definite log file name.
+The special names are "stdout" and "\-" \- they will force everything 
+to the stdout. Also, "syslog" name will redirect everything into
+the system log (syslog), as if the option "\fB\-\-syslog\fP" was set.
+.TP
+.B
+\fB\-\-alternate\-server\fP
+Option to set the "redirection" mode. The value of this option
+will be the address of the alternate server for UDP & TCP service in form of 
+<ip>[:<port>]. The server will send this value in the attribute
+ALTERNATE\-SERVER, with error 300, on ALLOCATE request, to the client.
+Client will receive only values with the same address family
+as the client network endpoint address family. 
+See RFC 5389 and RFC 5766 for ALTERNATE\-SERVER functionality description. 
+The client must use the obtained value for subsequent TURN communications.
+If more than one \fB\-\-alternate\-server\fP \fIoptions\fP are provided, then the functionality
+can be more accurately described as "load\-balancing" than a mere "redirection". 
+If the port number is omitted, then the default port 
+number 3478 for the UDP/TCP protocols will be used.
+Colon (:) characters in IPv6 addresses may conflict with the syntax of 
+the option. To alleviate this conflict, literal IPv6 addresses are enclosed 
+in square brackets in such resource identifiers, for example: 
+[2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478 . 
+Multiple alternate servers can be set. They will be used in the
+round\-robin manner. All servers in the pool are considered of equal weight and 
+the load will be distributed equally. For example, if we have 4 alternate servers, 
+then each server will receive 25% of ALLOCATE requests. An alternate TURN server 
+address can be used more than one time with the alternate\-server option, so this 
+can emulate "weighting" of the servers. 
+.TP
+.B
+\fB\-\-tls\-alternate\-server\fP
+Option to set alternative server for TLS & DTLS services in form of 
+<ip>:<port>. If the port number is omitted, then the default port 
+number 5349 for the TLS/DTLS protocols will be used. See the previous option for the 
+functionality description.
+.TP
+.B
+\fB\-O\fP, \fB\-\-redis\-statsdb\fP
+Redis status and statistics database connection string, if used (default \- empty, 
+no Redis stats DB used). This database keeps allocations status information, and it can 
+be also used for publishing and delivering traffic and allocation event notifications.
+This database option can be used independently of \fB\-\-redis\-userdb\fP option,
+and actually Redis can be used for status/statistics and MySQL or PostgreSQL can
+be used for the user database.
+The connection string has the same parameters as redis\-userdb connection string.
+.TP
+.B
+\fB\-\-max\-allocate\-timeout\fP
+Max time, in seconds, allowed for full allocation establishment. 
+Default is 60 seconds.
+.PP
+\fB\-\-denied\-peer\-ip\fP=<IPaddr[\fB\-IPaddr\fP]>
+.PP
+\fB\-\-allowed\-peer\-ip\fP=<IPaddr[\fB\-IPaddr\fP]> Options to ban or allow specific ip addresses or ranges 
+of ip addresses. If an ip address is specified as both allowed and denied, then 
+the ip address is considered to be allowed. This is useful when you wish to ban
+a range of ip addresses, except for a few specific ips within that range.
+This can be used when you do not want users of the turn server to be able to access
+machines reachable by the turn server, but would otherwise be unreachable from the 
+internet (e.g. when the turn server is sitting behind a NAT). The 'white" and "black" peer 
+IP ranges can also be dynamically changed in the database. 
+The allowed/denied addresses (white/black lists) rules are very simple:
+.RS
+.IP 1) 4
+If there is no rule for an address, then it is allowed;
+.IP 2) 4
+If there is an "allowed" rule that fits the address then it is allowed \- no matter what;
+.IP 3) 4
+If there is no "allowed" rule that fits the address, and if there is a "denied" rule that
+fits the address, then it is denied.
+.RE
+.TP
+.B
+\fB\-\-pidfile\fP
+File name to store the pid of the process.
+Default is /var/run/turnserver.pid (if superuser account is used) or
+/var/tmp/turnserver.pid .
+.TP
+.B
+\fB\-\-proc\-user\fP
+User name to run the process. After the initialization, the \fIturnserver\fP process
+will make an attempt to change the current user ID to that user.
+.TP
+.B
+\fB\-\-proc\-group\fP
+Group name to run the process. After the initialization, the \fIturnserver\fP process
+will make an attempt to change the current group ID to that group.
+.TP
+.B
+\fB\-\-cli\-ip\fP
+Local system IP address to be used for CLI management interface.
+The \fIturnserver\fP process can be accessed for management with telnet,
+at this IP address and on the CLI port (see the next parameter). 
+Default value is 127.0.0.1. You can use telnet or putty (in telnet mode)
+to access the CLI management interface. 
+.TP
+.B
+\fB\-\-cli\-port\fP
+CLI management interface listening port. Default is 5766.
+.TP
+.B
+\fB\-\-cli\-password\fP
+CLI access password. Default is empty (no password).
+.TP
+.B
+\fB\-\-cli\-max\-output\-sessions\fP
+Maximum number of output sessions in ps CLI command.
+This value can be changed on\-the\-fly in CLI. The default value is 256.
+.TP
+.B
+\fB\-\-ne\fP=[1|2|3]
+Set network engine type for the process (for internal purposes).
+.PP
+==================================
+.SH LOAD BALANCE AND PERFORMANCE TUNING
+
+This topic is covered in the wiki page:
+.PP
+http://code.google.com/p/coturn/wiki/turn_performance_and_load_balance
+.PP
+===================================
+.SH WEBRTC USAGE
+
+This is a set of notes for the WebRTC users:
+.IP 1) 4
+WebRTC uses long\-term authentication mechanism, so you have to use \fB\-a\fP
+option (or \fB\-\-lt\-cred\-mech\fP). WebRTC relaying will not work with anonymous access 
+or with short\-term authentication. With \fB\-a\fP option, do not forget to set the 
+default realm (\fB\-r\fP option). You will also have to set up the user accounts, 
+for that you have a number of \fIoptions\fP:
+.PP
+.nf
+.fam C
+        a) command\-line options (\-u).
+
+        b) userdb config file.
+
+        c) a database table (PostgreSQL or MySQL). You will have to set keys with 
+        turnadmin utility (see docs and wiki for turnadmin). You cannot use open passwords 
+        in the database.
+
+        d) Redis key/value pair(s), if Redis is used. You key use either keys or 
+        open passwords with Redis; see turndb/testredisdbsetup.sh file.  
+
+        e) You also can use the TURN REST API. You will need shared secret(s) set
+        either  through the command line option, or through the config file, or through
+        the database table or Redis key/value pairs.  
+
+.fam T
+.fi
+.IP 2) 4
+Usually WebRTC uses fingerprinting (\fB\-f\fP).
+.IP 3) 4
+\fB\-v\fP option may be nice to see the connected clients.
+.IP 4) 4
+\fB\-X\fP is needed if you are running your TURN server behind a NAT.
+.IP 5) 4
+\fB\-\-min\-port\fP and \fB\-\-max\-port\fP may be needed if you want to limit the relay endpoints ports
+number range.
+.PP
+===================================
+.SH TURN REST API
+
+In WebRTC, the browser obtains the TURN connection information from the web
+server. This information is a secure information \- because it contains the 
+necessary TURN credentials. As these credentials are transmitted over the 
+public networks, we have a potential security breach.
+.PP
+If we have to transmit a valuable information over the public network, 
+then this information has to have a limited lifetime. Then the guy who 
+obtains this information without permission will be able to perform 
+only limited damage.
+.PP
+This is how the idea of TURN REST API \- time\-limited TURN credentials \- 
+appeared. This security mechanism is based upon the long\-term credentials 
+mechanism. The main idea of the REST API is that the web server provides 
+the credentials to the client, but those credentials can be used only 
+limited time by an application that has to create a TURN server connection.
+.PP
+The "classic" long\-term credentials mechanism (LTCM) is described here:
+.PP
+http://tools.ietf.org/html/rfc5389#section\-10.2
+http://tools.ietf.org/html/rfc5389#section\-15.4
+.PP
+For authentication, each user must know two things: the username and the 
+password. Optionally, the user must supply the ORIGIN value, so that the 
+server can figure out the realm to be used for the user. The nonce and 
+the realm values are supplied by the TURN server. But LTCM is not saying 
+anything about the nature and about the persistence 
+of the username and of the password; and this is used by the REST API.
+.PP
+In the TURN REST API, there is no persistent passwords for users. A user has 
+just the username. The password is always temporary, and it is generated by 
+the web server on\-demand, when the user accesses the WebRTC page. And, 
+actually, a temporary one\-time session only, username is provided to the user, 
+too. 
+.PP
+The temporary user is generated as:
+.PP
+temporary\-username="timestamp" + ":" + "username"
+.PP
+where username is the persistent user name, and the timestamp format is just 
+seconds sinse 1970 \- the same value as \fBtime\fP(NULL) function returns.
+.PP
+The temporary password is obtained as HMAC\-SHA1 function over the temporary
+username, with shared secret as the HMAC key, and then the result is encoded:
+.PP
+temporary\-password = \fBbase64_encode\fP(hmac\-sha1(shared\-secret, temporary\-username))
+.PP
+Both the TURN server and the web server know the same shared secret. How the
+shared secret is distributed among the involved entities is left to the WebRTC
+deployment details \- this is beyond the scope of the TURN REST API.
+.PP
+So, a timestamp is used for the temporary password calculation, and this 
+timestamp can be retrieved from the temporary username. This information
+is valuable, but only temporary, while the timestamp is not expired. Without
+knowledge of the shared secret, a new temporary password cannot be generated.
+.PP
+This is all formally described in Justin's Uberti TURN REST API document
+that can be obtained following the link "TURN REST API" in the \fBTURN Server\fP
+project's page http://code.google.com/p/coturn/.
+.PP
+Once the temporary username and password are obtained by the client (browser)
+application, then the rest is just 'classic" long\-term credentials mechanism.
+For developers, we are going to describe it step\-by\-step below:
+.RS
+.IP \(bu 3
+a new TURN client sends a request command to the TURN server.
+.IP \(bu 3
+TURN server sees that this is a new client and the message is not
+authenticated.
+.IP \(bu 3
+the TURN server generates a random nonce string, and return the
+error 401 to the client, with nonce and realm included.
+.IP \(bu 3
+the client sees the 401 error and it extracts two values from
+the error response: the nonce and the realm.
+.IP \(bu 3
+the client uses username, realm and password to produce a key:
+.PP
+.nf
+.fam C
+         key = MD5(username ":" realm ":" SASLprep(password))
+.fam T
+.fi
+(SASLprep is described here: http://tools.ietf.org/html/rfc4013)
+.IP \(bu 3
+the client forms a new request, adds username, realm and nonce to the
+request. Then, the client calculates and adds the integrity field to 
+the request. This is the trickiest part of the process, and it is
+described in the end of section 15.4: 
+http://tools.ietf.org/html/rfc5389#section\-15.4
+.IP \(bu 3
+the client, optionally, adds the fingerprint field. This may be also
+a tricky procedure, described in section 15.5 of the same document. 
+WebRTC usually uses fingerprinted TURN messages.
+.IP \(bu 3
+the TURN server receives the request, reads the username.
+.IP \(bu 3
+then the TURN server checks that the nonce and the realm in the request
+are the valid ones.
+.IP \(bu 3
+then the TURN server calculates the key.
+.IP \(bu 3
+then the TURN server calculates the integrity field.
+.IP \(bu 3
+then the TURN server compares the calculated integrity field with the
+received one \- they must be the same. If the integrity fields differ, 
+then the request is rejected.
+.RE
+.PP
+In subsequent communications, the client may go with exactly the same 
+sequence, but for optimization usually the client, having already 
+information about realm and nonce, pre\-calculates the integrity string 
+for each request, so that the 401 error response becomes unnecessary. 
+The TURN server may use "\fB\-\-stale\-nonce\fP" option for extra security: in 
+some time, the nonce expires and the client will obtain 438 error response
+with the new nonce, and the client will have to start using the new nonce.
+.PP
+In subsequent communications, the sever and the client will always assume 
+the same password \- the original password becomes the session parameter and 
+is never expiring. So the password is not changing while the session is valid
+and unexpired. So, if the session is properly maintained, it may go forever, 
+even if the user password has been already changed (in the database). The 
+session simply is using the old password. Once the session got disconnected, 
+the client will have to use the new password to re\-connect (if the password 
+has been changed).
+.PP
+An example when a new shared secret is generated every hour by the TURN server
+box and then supplied to the web server, remotely, is provided in the script
+examples/scripts/restapi/shared_secret_maintainer.pl .
+.PP
+A very important thing is that the nonce must be totally random and it must be 
+different for different clients and different sessions. 
+.PP
+===================================
+.SH DATABASES
+
+For the user database, the \fIturnserver\fP has the following \fIoptions\fP:
+.IP 1) 4
+Users can be set in the command line, with multiple \fB\-u\fP or \fB\-\-user\fP \fIoptions\fP.
+Obviously, only a few users can be set that way, and their credentials are fixed 
+for the \fIturnserver\fP process lifetime.
+.IP 2) 4
+Users can be set in turnusers.conf flat file DB. The \fIturnserver\fP process periodically
+re\-reads this file, so the user accounts may be changed while the \fIturnserver\fP is running.
+But still a relatively small (up to a hundred ?) number of users can be handled that way.
+.IP 3) 4
+Users can be stored in PostgreSQL database, if the \fIturnserver\fP was compiled with PostgreSQL
+support. Each time \fIturnserver\fP checks user credentials, it reads the database (asynchronously,
+of course, so that the current flow of packets is not delayed in any way), so any change in the 
+database content is immediately visible by the \fIturnserver\fP. This is the way if you need the 
+best scalability. The schema for the database can be found in schema.sql file.
+For long\-term credentials, you have to set the "keys" for the users; the "keys" are generated 
+by the \fIturnadmin\fP utility. For the key generation, you need username, password and the realm. 
+All users in the database must use the same realm value; if down the road you will decide 
+to change the realm name, then you will have to re\-generate all user keys (that can be done 
+in a batch script). If you are using short\-term credentials, then you use open passwords 
+in the database; you will have to make sure that nobody can access the database outside of 
+the TURN server box. See the file turndb/testsqldbsetup.sql as an example.
+.IP 4) 4
+The same is true for MySQL database. The same schema file is applicable.
+The same considerations are applicable. 
+.IP 5) 4
+The same is true for the Redis database, but the Redis database has aa different schema \-
+it can be found (in the form of explanation) in schema.userdb.redis. 
+Also, in Redis you can store both "keys" and open passwords (for long term credentials) \- 
+the "open password" option is less secure but more convenient for low\-security environments. 
+For short\-term credentials, you will use open passwords only. See the file 
+turndb/testredisdbsetup.sh as an example. 
+.IP 6) 4
+Of course, the \fIturnserver\fP can be used in non\-secure mode, when users are allowed to establish
+sessions anonymously. But in most cases (like WebRTC) that will not work.
+.PP
+For the status and statistics database, there are two choices:
+.IP 1) 4
+The simplest choice is not to use it. Do not set \fB\-\-redis\-statsdb\fP option, and this functionality
+will be simply ignored.
+.IP 2) 4
+If you choose to use it, then set the \fB\-\-redis\-statsdb\fP option. This may be the same database
+as in \fB\-\-redis\-userdb\fP option, or it may be a different database. You may want to use different 
+database for security or convenience reasons. Also, you can use different database management
+systems for the user database and for the ststus and statistics database. For example, you can use 
+MySQL as the user database, and you can use redis for the statistics. Or you can use Redis for both.
+.PP
+So, we have 6 choices for the user management, and 2 choices for the statistics management. These
+two are totally independent. So, you have overall 6*2=12 ways to handle persistent information, 
+choose any for your convenience.
+.PP
+You do not have to handle the database information "manually" \- the \fIturnadmin\fP program can handle 
+everything for you. For PostgreSQL and MySQL you will just have to create an empty database
+with schema.sql SQL script. With Redis, you do not have to do even that \- just run \fIturnadmin\fP and 
+it will set the users for you (see the \fIturnadmin\fP manuals).
+.PP
+=================================
+.SH LIBRARIES
+
+In the lib/ sub\-directory the build process will create TURN client messaging library.
+In the include/ sub\-directory, the necessary include files will be placed.
+The C++ wrapper for the messaging functionality is located in TurnMsgLib.h header.
+An example of C++ code can be found in stunclient.c file. 
+.PP
+=================================
+.SH DOCS
+
+After installation, run the command:
+.PP
+$ man \fIturnserver\fP
+.PP
+or in the project root directory:
+.PP
+$ man \fB\-M\fP man \fIturnserver\fP
+.PP
+to see the man page.
+.PP
+In the docs/html subdirectory of the original archive tree, you will find the client library 
+reference. After the installation, it will be placed in PREFIX/share/doc/\fIturnserver\fP/html.
+.PP
+=================================
+.SH LOGS
+
+When the \fBTURN Server\fP starts, it makes efforts to create a log file turn_<pid>.log 
+in the following directories:
+.RS
+.IP \(bu 3
+/var/log
+.IP \(bu 3
+/log/
+.IP \(bu 3
+/var/tmp
+.IP \(bu 3
+/tmp
+.IP \(bu 3
+current directory
+.RE
+.PP
+If all efforts failed (due to the system permission settings) then all 
+log messages are sent only to the standard output of the process.
+.PP
+This behavior can be controlled by \fB\-\-log\-file\fP, \fB\-\-syslog\fP and \fB\-\-no\-stdout\-log\fP \fIoptions\fP.
+.PP
+=================================
+.SH TELNET CLI
+
+The \fIturnserver\fP process provides a telnet CLI access as statistics and basic management
+interface. By default, the \fIturnserver\fP starts a telnet CLI listener on IP 127.0.0.1 and
+port 5766. That can be changed by the command\-cline \fIoptions\fP of the \fIturnserver\fP process
+(see \fB\-\-cli\-ip\fP and \fB\-\-cli\-port\fP \fIoptions\fP). The full list of telnet CLI commands is provided
+in "help" command output in the telnet CLI.
+.PP
+=================================
+.SH CLUSTERS
+
+\fBTURN Server\fP can be a part of the cluster installation. But, to support the "even port" functionality 
+(RTP/RTCP streams pairs) the client requests from a particular IP must be delivered to the same 
+\fBTURN Server\fP instance, so it requires some networking setup massaging for the cluster. The reason is that 
+the RTP and RTCP relaying endpoints must be allocated on the same relay IP. It would be possible 
+to design a scheme with the application\-level requests forwarding (and we may do that later) but 
+it would affect the performance.
+.PP
+=================================
+.SH FILES
+
+/etc/turnserver.conf
+.PP
+/etc/turnuserdb.conf
+.PP
+/usr/local/etc/turnserver.conf
+.PP
+/usr/local/etc/turnuserdb.conf
+.PP
+=================================
+.SH DIRECTORIES
+
+/usr/local/share/\fIturnserver\fP
+.PP
+/usr/local/share/doc/\fIturnserver\fP
+.PP
+/usr/local/share/examples/\fIturnserver\fP
+.PP
+=================================
+.SH STANDARDS
+
+obsolete STUN RFC 3489
+.PP
+new STUN RFC 5389
+.PP
+TURN RFC 5766
+.PP
+TURN\-TCP extension RFC 6062
+.PP
+TURN IPv6 extension RFC 6156
+.PP
+STUN/TURN test vectors RFC 5769
+.PP
+STUN NAT behavior discovery RFC 5780
+.PP
+=================================
+.SH SEE ALSO
+
+\fIturnadmin\fP, \fIturnutils\fP
+.RE
+.PP
+======================================
+.SS  WEB RESOURCES
+
+project page:
+.PP
+http://code.google.com/p/coturn/
+.PP
+Wiki page:
+.PP
+http://code.google.com/p/coturn/wiki/Readme
+.PP
+forum:
+.PP
+https://groups.google.com/forum/?fromgroups=#!forum/turn\-server\-project\-rfc5766\-turn\-server/
+.RE
+.PP
+======================================
+.SS  AUTHORS
+
+Oleg Moskalenko <[email protected]>
+.PP
+Gabor Kovesdan http://kovesdan.org/
+.PP
+Daniel Pocock http://danielpocock.com/
+.PP
+John Selbie ([email protected])
+.PP
+Lee Sylvester <[email protected]>
+.PP
+Erik Johnston <[email protected]>
+.PP
+Roman Lisagor <[email protected]>
+.PP
+Vladimir Tsanev <[email protected]>
+.PP
+Po\-sheng Lin <[email protected]>
+.PP
+Peter Dunkley <[email protected]>
+.PP
+Mutsutoshi Yoshimoto <[email protected]>

+ 439 - 0
man/man1/turnutils.1

@@ -0,0 +1,439 @@
+.\" Text automatically generated by txt2man
+.TH TURN 1 "20 April 2014" "" ""
+.SH GENERAL INFORMATION
+
+A set of turnutils_* programs provides some utility functionality to be used
+for testing and for setting up the TURN server. 
+.TP
+.B
+1.
+\fIturnutils_uclient\fP: emulates multiple UDP,TCP,TLS or DTLS clients. 
+(this program is provided for the testing purposes only !)
+The compiled binary image of this program is located in bin/ 
+sub\-directory.
+.PP
+WARNING: the \fIturnutils_uclient\fP program is a primitive client application. 
+It does not implement the re\-transmission pattern that is necessary for 
+a correct TURN client implementation. In TURN, the retransmission burden 
+is lying almost entirely on the client application. We provide the messaging 
+functionality in the client library, but the client must implement 
+the correct Networking IO processing in the client program code.
+.TP
+.B
+2.
+\fIturnutils_peer\fP: a simple stateless UDP\-only "echo" server, 
+to be used as the final server in relay pattern ("peer"). For every incoming 
+UDP packet, it simply echoes it back.
+(this program is provided for the testing purposes only !) 
+When the test clients are communicating in the client\-to\-client manner 
+(when the "\fIturnutils_uclient\fP" program is used with "\fB\-y\fP" option) then the 
+\fIturnutils_peer\fP is not needed.
+.PP
+The compiled binary image of this program is located in bin/ subdirectory.
+.TP
+.B
+3.
+\fIturnutils_stunclient\fP: a simple STUN client example. 
+The compiled binary image of this program is located in bin/ subdirectory.
+.TP
+.B
+4.
+\fIturnutils_rfc5769check\fP: a utility that checks the correctness of the 
+STUN/TURN protocol implementation. This utility is used only for the compilation
+check procedure, it is not copied to the installation destination.
+.RE
+.PP
+
+.RS
+In the "examples/scripts" subdirectory, you will find the examples of command lines to be used 
+to run the programs. The scripts are meant to be run from examples/ subdirectory, for example:
+.PP
+$ cd examples
+.PP
+$ ./scripts/secure_relay.sh
+.PP
+=====================================
+.SS  NAME
+\fB
+\fBturnutils_uclient \fP\- this client emulation application is supplied for the test purposes only.
+\fB
+.SS  SYNOPSIS  
+
+$ \fIturnutils_uclient\fP [\fB\-tTSvsyhcxg\fP] [options] <TURN\-Server\-IP\-address>
+.SS  DESCRIPTION
+
+It was designed to simulate multiple clients. It uses asynch IO API in 
+libevent to handle multiple clients. A client connects to the relay, 
+negotiates the session, and sends multiple (configured number) messages to the server (relay), 
+expecting the same number of replies. The length of the messages is configurable. 
+The message is an arbitrary octet stream, but it can be configured as a string. 
+The number of the messages to send is configurable.
+.TP
+.B
+Flags:
+.TP
+.B
+\fB\-t\fP
+Use TCP for communications between client and TURN server (default is UDP).
+.TP
+.B
+\fB\-T\fP
+Use TCP for the relay transport (default \- UDP). Implies options \fB\-t\fP, \fB\-y\fP, \fB\-c\fP, 
+and ignores flags and options \fB\-s\fP, \fB\-e\fP, \fB\-r\fP and \fB\-g\fP.
+.TP
+.B
+\fB\-P\fP
+Passive TCP (RFC6062 with active peer). Implies \fB\-T\fP.
+.TP
+.B
+\fB\-S\fP
+Secure SSL connection: SSL/TLS for TCP, DTLS for UDP.
+.TP
+.B
+\fB\-U\fP
+Secure unencrypted connection (suite eNULL): SSL/TLS for TCP, DTLS for UDP.
+.TP
+.B
+\fB\-v\fP
+Verbose.
+.TP
+.B
+\fB\-s\fP
+Use "Send" method in TURN; by default, it uses TURN Channels.
+.TP
+.B
+\fB\-y\fP
+Use client\-to\-client connections: 
+RTP/RTCP pair of channels to another RTP/RTCP pair of channels.
+with this option the \fIturnutils_peer\fP application is not used,
+as the allocated relay endpoints are talking to each other.
+.TP
+.B
+\fB\-h\fP
+Hang on indefinitely after the last sent packet.
+.TP
+.B
+\fB\-c\fP
+Do not create rtcp connections.
+.TP
+.B
+\fB\-x\fP
+Request IPv6 relay address (RFC6156).
+.TP
+.B
+\fB\-X\fP
+IPv4 relay address explicitly requested.
+.TP
+.B
+\fB\-g\fP
+Set DONT_FRAGMENT parameter in TURN requests.
+.TP
+.B
+\fB\-A\fP
+use short\-term credentials mechanism for authentication. 
+By default, the program uses the long\-term credentials mechanism 
+if authentication is required.
+.TP
+.B
+\fB\-D\fP
+Do mandatory channel padding even for UDP (like pjnath).
+.TP
+.B
+\fB\-N\fP
+do negative tests (some limited cases only).
+.TP
+.B
+\fB\-R\fP
+do negative protocol tests.
+.TP
+.B
+\fB\-O\fP
+DOS attack mode.
+.TP
+.B
+\fB\-H\fP
+SHA256 digest function for message integrity calculation.
+Without this option, by default, SHA1 is used.
+.TP
+.B
+\fB\-M\fP
+Use TURN ICE Mobility.
+.TP
+.B
+\fB\-I\fP
+Do not set permissions on TURN relay endpoints
+(for testing the non\-standard server relay functionality).
+.TP
+.B
+\fB\-G\fP
+Generate extra requests (create permissions, channel bind).
+.TP
+.B
+Options with required values:
+.TP
+.B
+\fB\-l\fP
+Message length (Default: 100 Bytes).
+.TP
+.B
+\fB\-i\fP
+Certificate file (for secure connections only, optional).
+.TP
+.B
+\fB\-k\fP
+Private key file (for secure connections only).
+.TP
+.B
+\fB\-E\fP
+CA file for server certificate verification,
+if the server certificate to be verified.
+.TP
+.B
+\fB\-p\fP
+\fBTURN Server\fP port (Defaults: 3478 unsecure, 5349 secure).
+.TP
+.B
+\fB\-n\fP
+Number of messages to send (Default: 5).
+.TP
+.B
+\fB\-d\fP
+Local interface device (optional, Linux only).
+.TP
+.B
+\fB\-L\fP
+Local IP address (optional).
+.TP
+.B
+\fB\-m\fP
+Number of clients (Default: 1, 2 or 4, depending on options).
+.TP
+.B
+\fB\-e\fP
+Peer address.
+.TP
+.B
+\fB\-r\fP
+Peer port (Default: 3480).
+.TP
+.B
+\fB\-z\fP
+Per\-session packet interval in milliseconds (Default: 20).
+.TP
+.B
+\fB\-u\fP
+STUN/TURN user name.
+.TP
+.B
+\fB\-w\fP
+STUN/TURN user password.
+.TP
+.B
+\fB\-W\fP
+TURN REST API authentication secret. Is not compatible with \fB\-A\fP flag.
+.TP
+.B
+\fB\-C\fP
+This is the timestamp/username separator symbol (character) in 
+TURN REST API. The default value is :.
+.TP
+.B
+\fB\-F\fP
+Cipher suite for TLS/DTLS. Default value is DEFAULT.
+.PP
+See the examples in the "examples/scripts" directory.
+.PP
+======================================
+.SS  NAME
+\fB
+\fBturnutils_peer \fP\- a simple UDP\-only echo backend server.
+\fB
+.SS  SYNOPSYS
+
+$ \fIturnutils_peer\fP [\fB\-v\fP] [options]
+.SS  DESCRIPTION
+
+This application is used for the test purposes only, as a peer for the \fIturnutils_uclient\fP application.
+.TP
+.B
+Options with required values:
+.TP
+.B
+\fB\-p\fP
+Listening UDP port (Default: 3480).
+.TP
+.B
+\fB\-d\fP
+Listening interface device (optional)
+.TP
+.B
+\fB\-L\fP
+Listening address of \fIturnutils_peer\fP server. Multiple listening addresses can be used, IPv4 and IPv6.
+If no listener \fBaddress\fP(es) defined, then it listens on all IPv4 and IPv6 addresses.
+.TP
+.B
+\fB\-v\fP
+Verbose
+.PP
+========================================
+.SS  NAME
+\fB
+\fBturnutils_stunclient \fP\- a basic STUN client.
+\fB
+.SS  SYNOPSIS
+.nf
+.fam C
+
+$ \fIturnutils_stunclient\fP [\fIoptions\fP] <STUN\-Server\-IP\-address>
+
+.fam T
+.fi
+.fam T
+.fi
+.SS  DESCRIPTION
+
+It sends a "new" STUN RFC 5389 request (over UDP) and shows the reply information.
+.TP
+.B
+Options with required values:
+.TP
+.B
+\fB\-p\fP
+STUN server port (Default: 3478).
+.TP
+.B
+\fB\-L\fP
+Local address to use (optional).
+.TP
+.B
+\fB\-f\fP
+Force RFC 5780 processing.
+.PP
+The \fIturnutils_stunclient\fP program checks the results of the first request, 
+and if it finds that the STUN server supports RFC 5780 
+(the binding response reveals that) then the \fIturnutils_stunclient\fP makes a couple more 
+requests with different parameters, to demonstrate the NAT discovery capabilities.
+.PP
+This utility does not support the "old" "classic" STUN protocol (RFC 3489).
+.PP
+=====================================
+.SS  NAME
+\fB
+\fBturnutils_rfc5769check \fP\- a utility that tests the correctness of STUN protocol implementation.
+\fB
+.SS  SYNOPSIS
+.nf
+.fam C
+
+$ \fIturnutils_rfc5769check\fP
+
+.fam T
+.fi
+.fam T
+.fi
+.SS  DESCRIPTION
+
+\fIturnutils_rfc5769check\fP tests the correctness of STUN protocol implementation 
+against the test vectors predefined in RFC 5769 and prints the results of the 
+tests on the screen. This utility is used only for the compilation
+check procedure, it is not copied to the installation destination.
+.TP
+.B
+Usage:
+.PP
+$ \fIturnutils_rfc5769check\fP
+.PP
+===================================
+.SH DOCS
+
+After installation, run the command:
+.PP
+$ man \fIturnutils\fP
+.PP
+or in the project root directory:
+.PP
+$ man \fB\-M\fP man \fIturnutils\fP
+.PP
+to see the man page.
+.PP
+=====================================
+.SH FILES
+
+/etc/turnserver.conf
+.PP
+/etc/turnuserdb.conf
+.PP
+/usr/local/etc/turnserver.conf
+.PP
+/usr/local/etc/turnuserdb.conf
+.PP
+=================================
+.SH DIRECTORIES
+
+/usr/local/share/\fIturnserver\fP
+.PP
+/usr/local/share/doc/\fIturnserver\fP
+.PP
+/usr/local/share/examples/\fIturnserver\fP
+.PP
+===================================
+.SH STANDARDS
+
+new STUN RFC 5389
+.PP
+TURN RFC 5766
+.PP
+TURN\-TCP extension RFC 6062
+.PP
+TURN IPv6 extension RFC 6156
+.PP
+STUN/TURN test vectors RFC 5769
+.PP
+STUN NAT behavior discovery RFC 5780
+.PP
+====================================
+.SH SEE ALSO
+
+\fIturnserver\fP, \fIturnadmin\fP
+.RE
+.PP
+======================================
+.SS  WEB RESOURCES
+
+project page:
+.PP
+http://code.google.com/p/coturn/
+.PP
+Wiki page:
+.PP
+http://code.google.com/p/coturn/wiki/Readme
+.PP
+forum:
+.PP
+https://groups.google.com/forum/?fromgroups=#!forum/turn\-server\-project\-rfc5766\-turn\-server/
+.RE
+.PP
+======================================
+.SS  AUTHORS
+
+Oleg Moskalenko <[email protected]>
+.PP
+Gabor Kovesdan http://kovesdan.org/
+.PP
+Daniel Pocock http://danielpocock.com/
+.PP
+John Selbie ([email protected])
+.PP
+Lee Sylvester <[email protected]>
+.PP
+Erik Johnston <[email protected]>
+.PP
+Roman Lisagor <[email protected]>
+.PP
+Vladimir Tsanev <[email protected]>
+.PP
+Po\-sheng Lin <[email protected]>
+.PP
+Peter Dunkley <[email protected]>
+.PP
+Mutsutoshi Yoshimoto <[email protected]>

+ 1 - 0
man/man1/turnutils_peer.1

@@ -0,0 +1 @@
+turnutils.1

+ 1 - 0
man/man1/turnutils_stunclient.1

@@ -0,0 +1 @@
+turnutils.1

+ 1 - 0
man/man1/turnutils_uclient.1

@@ -0,0 +1 @@
+turnutils.1

+ 35 - 0
postinstall.txt

@@ -0,0 +1,35 @@
+==================================================================
+
+1) If you system supports automatic start-up system daemon services, 
+the, to enable the turnserver as an automatically started system 
+service, you have to:
+
+	a) Create and edit /etc/turnserver.conf or 
+	/usr/local/etc/turnserver.conf . 
+	Use /usr/local/etc/turnserver.conf.default as an example.
+
+	b) For user accounts settings, if using the turnserver 
+	with authentication: create and edit /etc/turnuserdb.conf 
+	file, or set up PostgreSQL or MySQL or Redis database for user accounts.
+	Use /usr/local/etc/turnuserdb.conf.default as example for flat file DB,
+	or use /usr/local/share/turnserver/schema.sql as SQL database schema,
+	or use /usr/local/share/turnserver/schema.userdb.redis as Redis
+	database schema description and/or /usr/local/share/turnserver/schema.stats.redis
+	as Redis status & statistics database schema description.
+
+	c) add whatever is necessary to enable start-up daemon for the /usr/local/bin/turnserver.
+     
+2) If you do not want the turnserver to be a system service, 
+   then you can start/stop it "manually", using the "turnserver" 
+   executable with appropriate options (see the documentation).
+   
+3) To create database schema, use schema in file /usr/local/share/turnserver/schema.sql.
+   
+4) For additional information, run:
+ 
+   $ man turnserver
+   $ man turnadmin
+   $ man turnutils
+	
+==================================================================
+ 

+ 98 - 0
rpm/CentOS6.pre.build.sh

@@ -0,0 +1,98 @@
+#!/bin/bash
+
+# CentOS6 preparation script.
+
+CPWD=`pwd`
+
+. ./common.pre.build.sh
+
+cd ${CPWD}
+
+EPELRPM=epel-release-6-8.noarch.rpm
+LIBEVENT_MAJOR_VERSION=2
+LIBEVENT_VERSION=${LIBEVENT_MAJOR_VERSION}.0.21
+LIBEVENT_DISTRO=libevent-${LIBEVENT_VERSION}-stable.tar.gz
+LIBEVENT_SPEC_DIR=libevent.rpm
+LIBEVENTSPEC_SVN_URL=${TURNSERVER_SVN_URL}/${LIBEVENT_SPEC_DIR}
+LIBEVENT_SPEC_FILE=libevent.spec
+
+# Common packs
+
+PACKS="mysql-devel"
+sudo yum -y install ${PACKS}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "Cannot install package(s) ${PACKS}"
+    cd ${CPWD}
+    exit -1
+fi
+
+# Libevent2:
+
+cd ${BUILDDIR}/SOURCES
+if ! [ -f  ${LIBEVENT_DISTRO} ] ; then
+    wget ${WGETOPTIONS} https://github.com/downloads/libevent/libevent/${LIBEVENT_DISTRO}
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+	cd ${CPWD}
+	exit -1
+    fi
+fi
+
+if ! [ -f ${BUILDDIR}/SPECS/${LIBEVENT_SPEC_FILE} ] ; then 
+    cd ${BUILDDIR}/tmp
+    rm -rf ${LIBEVENT_SPEC_DIR}
+    svn export ${LIBEVENTSPEC_SVN_URL} ${LIBEVENT_SPEC_DIR}
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+	cd ${CPWD}
+	exit -1
+    fi
+    
+    if ! [ -f ${LIBEVENT_SPEC_DIR}/${LIBEVENT_SPEC_FILE} ] ; then
+	echo "ERROR: cannot download ${LIBEVENT_SPEC_FILE} file"
+	cd ${CPWD}
+	exit -1
+    fi
+
+    cp ${LIBEVENT_SPEC_DIR}/${LIBEVENT_SPEC_FILE} ${BUILDDIR}/SPECS
+fi
+
+cd ${BUILDDIR}/SPECS
+rpmbuild -ba ${BUILDDIR}/SPECS/${LIBEVENT_SPEC_FILE}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    cd ${CPWD}
+    exit -1
+fi
+
+PACK=${BUILDDIR}/RPMS/${ARCH}/libevent-${LIBEVENT_MAJOR_VERSION}*.rpm
+sudo rpm ${RPMOPTIONS} ${PACK}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "Cannot install packages ${PACK}"
+    cd ${CPWD}
+    exit -1
+fi
+
+PACK=${BUILDDIR}/RPMS/${ARCH}/libevent-devel*.rpm
+sudo rpm ${RPMOPTIONS} ${PACK}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "Cannot install packages ${PACK}"
+    cd ${CPWD}
+    exit -1
+fi
+
+# EPEL (for hiredis)
+
+cd ${CPWD}
+./epel.install.sh
+ 
+# Platform file
+
+echo "CentOS6.5" > ${BUILDDIR}/platform
+
+cp ${CPWD}/epel.install.sh ${BUILDDIR}/install.sh
+
+cd ${CPWD}

+ 20 - 0
rpm/Fedora.pre.build.sh

@@ -0,0 +1,20 @@
+#!/bin/bash
+
+CPWD=`pwd`
+
+# Fedora preparation script.
+
+. ./common.pre.build.sh
+
+PACKS="libevent-devel mariadb-devel"
+sudo yum -y install ${PACKS}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "Cannot install package(s) ${PACKS}"
+    cd ${CPWD}
+    exit -1
+fi
+
+echo "Fedora20" > ${BUILDDIR}/platform
+
+cd ${CPWD}

+ 43 - 0
rpm/build.instructions.txt

@@ -0,0 +1,43 @@
+MANUAL PROCESS FOR CENTOS 6:
+
+
+The first thing you need to build/use the TURN server with CentOS is to build and install libevent 2.x.x.  CentOS 6 ships with libevent 1.x.x.  You can find a .spec file to build libevent 2.x.x here: https://github.com/crocodilertc/libevent
+
+To build libevent:
+
+    1) Install the dependencies for building libevent: gcc, make, redhat-rpm-config, doxygen, openssl-devel, rpm-build
+    2) $ mkdir ~/rpmbuild
+    3) $ mkdir ~/rpmbuild/SOURCES
+    4) $ mkdir ~/rpmbuild/SPECS
+    5) Put the tarball for libevent (https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz) and put it into ~/rpmbuild/SOURCES
+    6) Put the .spec for libevent (https://raw.github.com/crocodilertc/libevent/master/libevent.spec) into ~/rpmbuild/SPECS
+    7) Build the RPMs, "rpmbuild -ba ~/rpmbuild/SPECS/libevent.spec"
+
+
+To build the TURN server:
+
+    1) Install libevent and libevent-devel rpms
+    2) Install EPEL (http://fedoraproject.org/wiki/EPEL) - needed for hiredis
+    3) Install the dependencies for building the TURN server: gcc, make, redhat-rpm-config, openssl-devel, libevent-devel >= 2.0.0, 
+       mysql-devel, postgresql-devel, hiredis-devel
+    4) $ mkdir ~/rpmbuild
+    5) $ mkdir ~/rpmbuild/SOURCES
+    6) Export the TURN server from SVN, "svn export http://coturn.googlecode.com/svn/trunk/ turnserver-2.6.7.0"
+    7) Create a tarball, "tar zcf ~/rpmbuild/SOURCES/turnserver-2.6.7.0.tar.gz turnserver-2.6.7.0"
+    8) Build the RPMs, "rpmbuild -ta ~/rpmbuild/SOURCES/turnserver-2.6.7.0.tar.gz"
+
+
+AUTOMATED PROCESS FOR CENTOS 6:
+
+$ cd <...>/coturn/rpm
+$ ./CentOS6.pre.build.sh
+$ ./build.sh
+(then see the tarball in ~/rpmbuild/RPMS/<arch>)
+
+AUTOMATED PROCESS FOR Fedora:
+
+$ cd <...>/coturn/rpm
+$ ./Fedora.pre.build.sh
+$ ./build.sh
+(then see the tarball in ~/rpmbuild/RPMS/<arch>)
+

+ 14 - 0
rpm/build.settings.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# Common settings script.
+
+TURNVERSION=3.3.0.0
+BUILDDIR=~/rpmbuild
+ARCH=`uname -p`
+TURNSERVER_SVN_URL=http://coturn.googlecode.com/svn
+TURNSERVER_SVN_URL_VER=trunk
+
+WGETOPTIONS="--no-check-certificate"
+RPMOPTIONS="-ivh --force"
+
+

+ 98 - 0
rpm/build.sh

@@ -0,0 +1,98 @@
+#!/bin/bash
+
+CPWD=`pwd`
+
+. ./build.settings.sh
+
+# Required packages
+
+PACKS="postgresql-devel hiredis-devel"
+
+sudo yum -y install ${PACKS}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "Cannot install packages ${PACKS}"
+    cd ${CPWD}
+    exit -1
+fi
+
+# TURN
+
+cd ${BUILDDIR}/tmp
+rm -rf turnserver-${TURNVERSION}
+svn export ${TURNSERVER_SVN_URL}/${TURNSERVER_SVN_URL_VER}/ turnserver-${TURNVERSION}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    cd ${CPWD}
+    exit -1
+fi
+
+tar zcf ${BUILDDIR}/SOURCES/turnserver-${TURNVERSION}.tar.gz turnserver-${TURNVERSION}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    cd ${CPWD}
+    exit -1
+fi
+
+rpmbuild -ta ${BUILDDIR}/SOURCES/turnserver-${TURNVERSION}.tar.gz
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    cd ${CPWD}
+    exit -1
+fi
+
+# Make binary tarball
+
+cd ${BUILDDIR}/RPMS/${ARCH}
+mkdir -p di
+mv *debuginfo* di
+mv *devel* di
+rm -rf turnserver-${TURNVERSION}
+mkdir turnserver-${TURNVERSION}
+mv *.rpm turnserver-${TURNVERSION}/
+
+rm -rf turnserver-${TURNVERSION}/install.sh
+
+if [ -f ${BUILDDIR}/install.sh ] ; then
+    cat ${BUILDDIR}/install.sh > turnserver-${TURNVERSION}/install.sh
+else
+    echo "#!/bin/sh" > turnserver-${TURNVERSION}/install.sh
+fi
+
+cat <<EOF >>turnserver-${TURNVERSION}/install.sh
+
+sudo yum -y install openssl
+sudo yum -y install telnet
+  
+for i in *.rpm ; do
+
+  sudo yum -y install \${i}
+  ER=\$?
+  if ! [ \${ER} -eq 0 ] ; then
+    sudo rpm -Uvh \${i}
+    ER=\$?
+    if ! [ \${ER} -eq 0 ] ; then
+      sudo rpm -ivh --force \${i}
+      ER=\$?
+      if ! [ \${ER} -eq 0 ] ; then
+        echo "ERROR: cannot install package \${i}"
+        exit -1
+      fi
+    fi
+  fi
+done
+
+echo SUCCESS !
+
+EOF
+
+chmod a+x turnserver-${TURNVERSION}/install.sh
+
+cp ${CPWD}/uninstall.turnserver.sh turnserver-${TURNVERSION}/
+chmod a+x turnserver-${TURNVERSION}/uninstall.turnserver.sh
+
+PLATFORM=`cat ${BUILDDIR}/platform`
+
+tar cvfz turnserver-${TURNVERSION}-${PLATFORM}-${ARCH}.tar.gz turnserver-${TURNVERSION}
+
+cd ${CPWD}

+ 26 - 0
rpm/common.pre.build.sh

@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Common preparation script.
+
+. ./build.settings.sh
+
+# DIRS
+
+rm -rf ${BUILDDIR}
+
+mkdir -p ${BUILDDIR}
+mkdir -p ${BUILDDIR}/SOURCES
+mkdir -p ${BUILDDIR}/SPECS
+mkdir -p ${BUILDDIR}/RPMS
+mkdir -p ${BUILDDIR}/tmp
+
+# Common packs
+
+PACKS="make gcc redhat-rpm-config rpm-build doxygen openssl-devel svn"
+sudo yum -y install ${PACKS}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "Cannot install packages ${PACKS}"
+    exit -1
+fi
+

+ 39 - 0
rpm/epel.install.sh

@@ -0,0 +1,39 @@
+#!/bin/bash
+
+CPWD=`pwd`
+
+# Epel installation script
+
+EPEL=epel-release-6-8.noarch
+EPELRPM=${EPEL}.rpm
+BUILDDIR=~/rpmbuild
+WGETOPTIONS="--no-check-certificate"
+RPMOPTIONS="-ivh --force"
+
+mkdir -p ${BUILDDIR}
+mkdir -p ${BUILDDIR}/RPMS
+
+sudo yum -y install wget
+
+cd ${BUILDDIR}/RPMS
+if ! [ -f ${EPELRPM} ] ; then
+    wget ${WGETOPTIONS} http://download.fedoraproject.org/pub/epel/6/i386/${EPELRPM}
+    ER=$?
+    if ! [ ${ER} -eq 0 ] ; then
+	cd ${CPWD}
+	exit -1
+    fi
+fi
+
+PACK=${EPELRPM}
+sudo rpm ${RPMOPTIONS} ${PACK}
+ER=$?
+if ! [ ${ER} -eq 0 ] ; then
+    echo "Cannot install package ${PACK}"
+    cd ${CPWD}
+    exit -1
+fi
+
+cd ${CPWD}
+
+

+ 82 - 0
rpm/turnserver.init.el

@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# Startup script for TURN Server
+#
+# chkconfig: 345 85 15
+# description: RFC 5766 TURN Server
+#
+# processname: turnserver
+# pidfile: /var/run/turnserver.pid
+# config: /etc/turnserver/turnserver.conf
+#
+### BEGIN INIT INFO
+# Provides: turnserver
+# Required-Start: $local_fs $network
+# Short-Description: RFC 5766 TURN Server
+# Description: RFC 5766 TURN Server
+### END INIT INFO
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+TURN=/usr/bin/turnserver
+PROG=turnserver
+TURNCFG=/etc/turnserver/$PROG.conf
+PID_FILE=/var/run/$PROG.pid
+LOCK_FILE=/var/lock/subsys/$PROG
+DEFAULTS=/etc/sysconfig/$PROG
+RETVAL=0
+USER=turnserver
+
+start() {
+	echo -n $"Starting $PROG: "
+	daemon --user=$USER $TURN $OPTIONS
+	RETVAL=$?
+	if [ $RETVAL = 0 ]; then
+		pidofproc $TURN > $PID_FILE
+		RETVAL=$?
+		[ $RETVAL = 0 ] && touch $LOCK_FILE && success
+	fi
+	echo
+	return $RETVAL
+}
+
+stop() {
+	echo -n $"Stopping $PROG: "
+	killproc $TURN
+	RETVAL=$?
+	echo
+	[ $RETVAL = 0 ] && rm -f $LOCK_FILE $PID_FILE
+}
+
+[ -f $DEFAULTS ] && . $DEFAULTS
+OPTIONS="-o -c $TURNCFG $EXTRA_OPTIONS"
+
+# See how we were called.
+case "$1" in
+	start)
+		start
+		;;
+	stop)
+		stop
+		;;
+	status)
+		status $TURN
+		RETVAL=$?
+		;;
+	restart)
+		stop
+		start
+		;;
+	condrestart)
+		if [ -f $PID_FILE ] ; then
+			stop
+			start
+		fi
+		;;
+	*)
+		echo $"Usage: $PROG {start|stop|restart|condrestart|status|help}"
+		exit 1
+esac
+
+exit $RETVAL

+ 15 - 0
rpm/turnserver.service.fc

@@ -0,0 +1,15 @@
+[Unit]
+Description=coturn
+Documentation=man:coturn(1) man:turnadmin(1) man:turnserver(1)
+After=syslog.target network.target
+
+[Service]
+Type=forking
+EnvironmentFile=/etc/sysconfig/turnserver
+PIDFile=/var/run/turnserver.pid
+ExecStart=/usr/bin/turnserver -o -c /etc/turnserver/turnserver.conf $EXTRA_OPTIONS
+ExecStopPost=/usr/bin/rm -f /var/run/turnserver.pid
+Restart=on-abort
+
+[Install]
+WantedBy=multi-user.target

+ 358 - 0
rpm/turnserver.spec

@@ -0,0 +1,358 @@
+Name:		turnserver
+Version:	3.3.0.0
+Release:	0%{dist}
+Summary:	Coturn TURN Server
+
+Group:		System Environment/Libraries
+License:	BSD
+URL:		https://code.google.com/p/coturn/ 
+Source0:	http://turnserver.open-sys.org/downloads/v%{version}/%{name}-%{version}.tar.gz
+
+BuildRequires:	gcc, make, redhat-rpm-config
+BuildRequires:	openssl-devel, libevent-devel >= 2.0.0, postgresql-devel
+BuildRequires:	hiredis-devel
+Requires:	openssl, libevent >= 2.0.0, mysql-libs, postgresql-libs
+Requires:	hiredis, perl-DBI, perl-libwww-perl
+Requires:	telnet
+%if 0%{?el6}
+BuildRequires:	epel-release, mysql-devel
+Requires:	epel-release, mysql-libs
+%else
+BuildRequires:	mariadb-devel
+Requires: 	mariadb-libs
+%endif
+
+
+%description
+The TURN Server is a VoIP media traffic NAT traversal server and gateway. It
+can be used as a general-purpose network traffic TURN server/gateway, too.
+
+This implementation also includes some extra features. Supported RFCs:
+
+TURN specs:
+- RFC 5766 - base TURN specs
+- RFC 6062 - TCP relaying TURN extension
+- RFC 6156 - IPv6 extension for TURN
+- Experimental DTLS support as client protocol.
+
+STUN specs:
+- RFC 3489 - "classic" STUN
+- RFC 5389 - base "new" STUN specs
+- RFC 5769 - test vectors for STUN protocol testing
+- RFC 5780 - NAT behavior discovery support
+
+The implementation fully supports the following client-to-TURN-server protocols:
+- UDP (per RFC 5766)
+- TCP (per RFC 5766 and RFC 6062)
+- TLS (per RFC 5766 and RFC 6062); SSL3/TLS1.0/TLS1.1/TLS1.2; SSL2 wrapping
+  supported
+- DTLS (experimental non-standard feature)
+
+Supported relay protocols:
+- UDP (per RFC 5766)
+- TCP (per RFC 6062)
+
+Supported user databases (for user repository, with passwords or keys, if
+authentication is required):
+- Flat files
+- MySQL
+- PostgreSQL
+- Redis
+
+Redis can also be used for status and statistics storage and notification.
+
+Supported TURN authentication mechanisms:
+- short-term
+- long-term
+- TURN REST API (a modification of the long-term mechanism, for time-limited
+  secret-based authentication, for WebRTC applications)
+
+The load balancing can be implemented with the following tools (either one or a
+combination of them):
+- network load-balancer server
+- DNS-based load balancing
+- built-in ALTERNATE-SERVER mechanism.
+
+
+%package 	utils
+Summary:	TURN client utils
+Group:		System Environment/Libraries
+Requires:	turnserver-client-libs = %{version}-%{release}
+
+%description 	utils
+This package contains the TURN client utils.
+
+%package 	client-libs
+Summary:	TURN client library
+Group:		System Environment/Libraries
+Requires:	openssl, libevent >= 2.0.0
+
+%description	client-libs
+This package contains the TURN client library.
+
+%package 	client-devel
+Summary:	TURN client development headers.
+Group:		Development/Libraries
+Requires:	turnserver-client-libs = %{version}-%{release}
+
+%description 	client-devel
+This package contains the TURN client development headers.
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+PREFIX=%{_prefix} CONFDIR=%{_sysconfdir}/%{name} EXAMPLESDIR=%{_datadir}/%{name} \
+	MANPREFIX=%{_datadir} LIBDIR=%{_libdir} MORECMD=cat ./configure
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+DESTDIR=$RPM_BUILD_ROOT make install
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig
+install -m644 rpm/turnserver.sysconfig \
+		$RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/turnserver
+mv $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnuserdb.conf.default \
+	$RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnuserdb.conf
+%if 0%{?el6}
+cat $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnserver.conf.default | \
+    sed s/#syslog/syslog/g | \
+    sed s/#no-stdout-log/no-stdout-log/g > \
+    $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnserver.conf
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rc.d/init.d
+install -m755 rpm/turnserver.init.el \
+		$RPM_BUILD_ROOT/%{_sysconfdir}/rc.d/init.d/turnserver
+%else
+cat $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnserver.conf.default | \
+    sed s/#syslog/syslog/g | \
+    sed s/#no-stdout-log/no-stdout-log/g | \
+    sed s/#pidfile/pidfile/g > \
+    $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnserver.conf
+mkdir -p $RPM_BUILD_ROOT/%{_unitdir}
+install -m755 rpm/turnserver.service.fc \
+		$RPM_BUILD_ROOT/%{_unitdir}/turnserver.service
+%endif
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/turnserver.conf.default
+
+%clean
+rm -rf "$RPM_BUILD_ROOT"
+
+%pre
+%{_sbindir}/groupadd -r turnserver 2> /dev/null || :
+%{_sbindir}/useradd -r -g turnserver -s /bin/false -c "TURN Server daemon" -d \
+		%{_datadir}/%{name} turnserver 2> /dev/null || :
+
+%post
+%if 0%{?el6}
+/sbin/chkconfig --add turnserver
+%else
+/bin/systemctl --system daemon-reload
+%endif
+
+%preun
+if [ $1 = 0 ]; then
+%if 0%{?el6}
+	/sbin/service turnserver stop > /dev/null 2>&1
+	/sbin/chkconfig --del turnserver
+%else
+	/bin/systemctl stop turnserver.service
+	/bin/systemctl disable turnserver.service 2> /dev/null
+%endif
+fi
+
+%postun
+%if 0%{?fedora}
+/bin/systemctl --system daemon-reload
+%endif
+
+%files
+%defattr(-,root,root)
+%{_bindir}/turnserver
+%{_bindir}/turnadmin
+%{_mandir}/man1/coturn.1.gz
+%{_mandir}/man1/turnserver.1.gz
+%{_mandir}/man1/turnadmin.1.gz
+%dir %attr(-,turnserver,turnserver) %{_sysconfdir}/%{name}
+%config(noreplace) %attr(0644,turnserver,turnserver) %{_sysconfdir}/%{name}/turnserver.conf
+%config(noreplace) %attr(0644,turnserver,turnserver) %{_sysconfdir}/%{name}/turnuserdb.conf
+%config(noreplace) %{_sysconfdir}/sysconfig/turnserver
+%if 0%{?el6}
+%config %{_sysconfdir}/rc.d/init.d/turnserver
+%else
+%config %{_unitdir}/turnserver.service
+%endif
+%dir %{_docdir}/%{name}
+%{_docdir}/%{name}/LICENSE
+%{_docdir}/%{name}/INSTALL
+%{_docdir}/%{name}/postinstall.txt
+%{_docdir}/%{name}/README.turnadmin
+%{_docdir}/%{name}/README.turnserver
+%{_docdir}/%{name}/schema.sql
+%{_docdir}/%{name}/schema.stats.redis
+%{_docdir}/%{name}/schema.userdb.redis
+%dir %{_datadir}/%{name}
+%{_datadir}/%{name}/schema.sql
+%{_datadir}/%{name}/schema.stats.redis
+%{_datadir}/%{name}/schema.userdb.redis
+%{_datadir}/%{name}/testredisdbsetup.sh
+%{_datadir}/%{name}/testsqldbsetup.sql
+%dir %{_datadir}/%{name}/etc
+%{_datadir}/%{name}/etc/turn_server_cert.pem
+%{_datadir}/%{name}/etc/turn_server_pkey.pem
+%{_datadir}/%{name}/etc/turnserver.conf
+%{_datadir}/%{name}/etc/turnuserdb.conf
+%dir %{_datadir}/%{name}/scripts
+%{_datadir}/%{name}/scripts/peer.sh
+%{_datadir}/%{name}/scripts/readme.txt
+%dir %{_datadir}/%{name}/scripts/basic
+%{_datadir}/%{name}/scripts/basic/dos_attack.sh
+%{_datadir}/%{name}/scripts/basic/relay.sh
+%{_datadir}/%{name}/scripts/basic/tcp_client.sh
+%{_datadir}/%{name}/scripts/basic/tcp_client_c2c_tcp_relay.sh
+%{_datadir}/%{name}/scripts/basic/udp_c2c_client.sh
+%{_datadir}/%{name}/scripts/basic/udp_client.sh
+%dir %{_datadir}/%{name}/scripts/loadbalance
+%{_datadir}/%{name}/scripts/loadbalance/master_relay.sh
+%{_datadir}/%{name}/scripts/loadbalance/slave_relay_1.sh
+%{_datadir}/%{name}/scripts/loadbalance/slave_relay_2.sh
+%{_datadir}/%{name}/scripts/loadbalance/tcp_c2c_tcp_relay.sh
+%{_datadir}/%{name}/scripts/loadbalance/udp_c2c.sh
+%dir %{_datadir}/%{name}/scripts/longtermsecure
+%{_datadir}/%{name}/scripts/longtermsecure/secure_dos_attack.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_dtls_client.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_dtls_client_cert.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_tls_client_cert.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_relay.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_relay_cert.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_tcp_client.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_tcp_client_c2c_tcp_relay.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_tls_client.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_tls_client_c2c_tcp_relay.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_udp_c2c.sh
+%{_datadir}/%{name}/scripts/longtermsecure/secure_udp_client.sh
+%dir %{_datadir}/%{name}/scripts/longtermsecuredb
+%{_datadir}/%{name}/scripts/longtermsecuredb/secure_relay_with_db_mysql.sh
+%{_datadir}/%{name}/scripts/longtermsecuredb/secure_relay_with_db_psql.sh
+%{_datadir}/%{name}/scripts/longtermsecuredb/secure_relay_with_db_redis.sh
+%dir %{_datadir}/%{name}/scripts/restapi
+%{_datadir}/%{name}/scripts/restapi/secure_relay_secret.sh
+%{_datadir}/%{name}/scripts/restapi/secure_relay_secret_with_db_mysql.sh
+%{_datadir}/%{name}/scripts/restapi/secure_relay_secret_with_db_psql.sh
+%{_datadir}/%{name}/scripts/restapi/secure_relay_secret_with_db_redis.sh
+%{_datadir}/%{name}/scripts/restapi/secure_udp_client_with_secret.sh
+%{_datadir}/%{name}/scripts/restapi/shared_secret_maintainer.pl
+%dir %{_datadir}/%{name}/scripts/selfloadbalance
+%{_datadir}/%{name}/scripts/selfloadbalance/secure_dos_attack.sh
+%{_datadir}/%{name}/scripts/selfloadbalance/secure_relay.sh
+%dir %{_datadir}/%{name}/scripts/shorttermsecure
+%{_datadir}/%{name}/scripts/shorttermsecure/secure_relay_short_term_mech.sh
+%{_datadir}/%{name}/scripts/shorttermsecure/secure_tcp_client_c2c_tcp_relay_short_term.sh
+%{_datadir}/%{name}/scripts/shorttermsecure/secure_udp_client_short_term.sh
+%dir %{_datadir}/%{name}/scripts/mobile
+%{_datadir}/%{name}/scripts/mobile/mobile_relay.sh
+%{_datadir}/%{name}/scripts/mobile/mobile_dtls_client.sh
+%{_datadir}/%{name}/scripts/mobile/mobile_tcp_client.sh
+%{_datadir}/%{name}/scripts/mobile/mobile_tls_client_c2c_tcp_relay.sh
+%{_datadir}/%{name}/scripts/mobile/mobile_udp_client.sh
+
+%files 		utils
+%defattr(-,root,root)
+%{_bindir}/turnutils_peer
+%{_bindir}/turnutils_stunclient
+%{_bindir}/turnutils_uclient
+%{_mandir}/man1/turnutils.1.gz
+%{_mandir}/man1/turnutils_peer.1.gz
+%{_mandir}/man1/turnutils_stunclient.1.gz
+%{_mandir}/man1/turnutils_uclient.1.gz
+%dir %{_docdir}/%{name}
+%{_docdir}/%{name}/LICENSE
+%{_docdir}/%{name}/README.turnutils
+%dir %{_datadir}/%{name}
+%dir %{_datadir}/%{name}/etc
+%{_datadir}/%{name}/etc/turn_client_cert.pem
+%{_datadir}/%{name}/etc/turn_client_pkey.pem
+
+%files		client-libs
+%{_docdir}/%{name}/LICENSE
+%{_libdir}/libturnclient.a
+
+%files		client-devel
+%{_docdir}/%{name}/LICENSE
+%dir %{_includedir}/turn
+%{_includedir}/turn/ns_turn_defs.h
+%dir %{_includedir}/turn/client
+%{_includedir}/turn/client/ns_turn_ioaddr.h
+%{_includedir}/turn/client/ns_turn_msg_addr.h
+%{_includedir}/turn/client/ns_turn_msg_defs.h
+%{_includedir}/turn/client/ns_turn_msg.h
+%{_includedir}/turn/client/TurnMsgLib.h
+
+%changelog
+* Sun Feb 09 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.3.0.0
+* Tue Feb 04 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.2.6
+* Sat Jan 25 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.2.5
+* Fri Jan 24 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.2.4
+* Thu Jan 23 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.2.3
+* Tue Jan 21 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.2.2
+* Sat Jan 11 2014 Oleg Moskalenko <[email protected]>
+  - CPU optimization, added to 3.2.2.1
+* Mon Jan 06 2014 Oleg Moskalenko <[email protected]>
+  - Linux epoll performance improvements, added to 3.2.1.4
+* Mon Jan 06 2014 Oleg Moskalenko <[email protected]>
+  - Telnet client installation added to 3.2.1.3
+* Sun Jan 05 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.1.2
+* Fri Jan 03 2014 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.1.1
+* Thu Dec 26 2013 Oleg Moskalenko <[email protected]>
+  - Sync to 3.2.1.0
+* Wed Dec 25 2013 Oleg Moskalenko <[email protected]>
+  - Sync to 3.1.6.0
+* Mon Dec 23 2013 Oleg Moskalenko <[email protected]>
+  - Sync to 3.1.5.3
+* Fri Dec 20 2013 Oleg Moskalenko <[email protected]>
+  - Sync to 3.1.5.1
+* Thu Dec 19 2013 Oleg Moskalenko <[email protected]>
+  - Sync to 3.1.4.2
+* Sat Dec 14 2013 Oleg Moskalenko <[email protected]>
+  - Sync to 3.1.3.1
+* Wed Dec 11 2013 Oleg Moskalenko <[email protected]>
+  - OpenSSL installation fixed 3.1.2.3
+* Tue Dec 10 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 3.1.2.2
+* Mon Dec 09 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 3.1.2.1
+* Sun Dec 01 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 3.1.1.0
+* Sat Nov 30 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 3.0.2.1.
+* Thu Nov 28 2013 Oleg Moskalenko <[email protected]>
+  - Config file setting fixed: version 3.0.1.4.
+* Wed Nov 27 2013 Oleg Moskalenko <[email protected]>
+  - Config file setting fixed: version 3.0.1.3.
+* Mon Nov 25 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 3.0.1.2
+* Sun Nov 10 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 3.0.0.0
+* Fri Nov 8 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 2.6.7.2
+* Thu Nov 7 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 2.6.7.1
+* Sun Nov 3 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 2.6.7.0
+* Sat Nov 2 2013 Peter Dunkley <[email protected]>
+  - Added Fedora support
+* Thu Oct 31 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 2.6.6.2
+* Sun Oct 27 2013 Oleg Moskalenko <[email protected]>
+  - Updated to version 2.6.6.1
+* Sun Oct 27 2013 Peter Dunkley <[email protected]>
+  - Updated to version 2.6.6.0
+* Fri May 3 2013 Peter Dunkley <[email protected]>
+  - First version

+ 5 - 0
rpm/turnserver.sysconfig

@@ -0,0 +1,5 @@
+#
+# TURN Server startup options
+#
+
+EXTRA_OPTIONS=""

+ 19 - 0
rpm/uninstall.turnserver.sh

@@ -0,0 +1,19 @@
+#!/bin/sh
+
+for i in `rpm -q -a | grep turnserver-utils-3`
+do
+  echo $i
+  sudo rpm -e $i
+done
+
+for i in `rpm -q -a | grep turnserver-client-libs-3`
+do
+  echo $i
+  sudo rpm -e $i
+done
+
+for i in `rpm -q -a | grep turnserver.*-3`
+do
+  echo $i
+  sudo rpm -e $i
+done

+ 902 - 0
src/apps/common/apputils.c

@@ -0,0 +1,902 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "ns_turn_utils.h"
+#include "ns_turn_msg.h"
+
+#include "apputils.h"
+
+#include <event2/event.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <limits.h>
+#include <ifaddrs.h>
+#include <getopt.h>
+#include <locale.h>
+#include <libgen.h>
+#include <fcntl.h>
+
+#include <pthread.h>
+
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+
+/************************/
+
+int IS_TURN_SERVER = 0;
+
+/*********************** Sockets *********************************/
+
+int socket_set_nonblocking(evutil_socket_t fd)
+{
+#if defined(WIN32)
+	unsigned long nonblocking = 1;
+    ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
+#else
+    if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+        perror("O_NONBLOCK");
+        return -1;
+    }
+#endif
+    return 0;
+}
+
+void read_spare_buffer(evutil_socket_t fd)
+{
+	if(fd >= 0) {
+		static char buffer[65536];
+		recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT);
+	}
+}
+
+int set_sock_buf_size(evutil_socket_t fd, int sz0)
+{
+	int sz;
+
+	sz = sz0;
+	while (sz > 0) {
+		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*) (&sz), (socklen_t) sizeof(sz)) < 0) {
+			sz = sz / 2;
+		} else {
+			break;
+		}
+	}
+
+	if (sz < 1) {
+		perror("Cannot set socket rcv size");
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Cannot set rcv sock size %d on fd %d\n", sz0, fd);
+	}
+
+	sz = sz0;
+	while (sz > 0) {
+		if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void*) (&sz), (socklen_t) sizeof(sz)) < 0) {
+			sz = sz / 2;
+		} else {
+			break;
+		}
+	}
+
+	if (sz < 1) {
+		perror("Cannot set socket snd size");
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Cannot set snd sock size %d on fd %d\n", sz0, fd);
+	}
+
+	return 0;
+}
+
+int socket_tcp_set_keepalive(evutil_socket_t fd)
+{
+#ifdef SO_KEEPALIVE
+    /* Set the keepalive option active */
+    {
+	    int on = 1;
+	    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const void*)&on, (socklen_t) sizeof(on));
+    }
+#else
+    UNUSED_ARG(fd);
+#endif
+
+#ifdef SO_NOSIGPIPE
+    {
+    	 int on = 1;
+    	 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (const void*)&on, (socklen_t) sizeof(on));
+    }
+#endif
+
+    return 0;
+}
+
+int socket_set_reusable(evutil_socket_t fd, int flag)
+{
+
+	if (fd < 0)
+		return -1;
+	else {
+
+#if defined(WIN32)
+		int use_reuseaddr = IS_TURN_SERVER;
+#else
+		int use_reuseaddr = 1;
+#endif
+
+#if defined(SO_REUSEPORT)
+		if (use_reuseaddr) {
+			int on = flag;
+			setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &on, (socklen_t) sizeof(on));
+		}
+#endif
+
+#if defined(SO_REUSEADDR)
+		if (use_reuseaddr) {
+			int on = flag;
+			int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on));
+			if (ret < 0)
+				perror("SO_REUSEADDR");
+		}
+#endif
+
+		return 0;
+	}
+}
+
+int sock_bind_to_device(evutil_socket_t fd, const unsigned char* ifname) {
+
+	if (fd >= 0 && ifname && ifname[0]) {
+
+#if defined(SO_BINDTODEVICE)
+
+		struct ifreq ifr;
+		memset(&ifr, 0, sizeof(ifr));
+
+		strncpy(ifr.ifr_name, (const char*) ifname, sizeof(ifr.ifr_name));
+
+		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *) &ifr, sizeof(ifr)) < 0) {
+			if (errno == EPERM)
+				perror("You must obtain superuser privileges to bind a socket to device");
+			else
+				perror("Cannot bind socket to device");
+
+			return -1;
+		}
+
+		return 0;
+
+#endif
+
+	}
+
+	return 0;
+}
+
+int addr_connect(evutil_socket_t fd, const ioa_addr* addr, int *out_errno)
+{
+	if (!addr || fd < 0)
+		return -1;
+	else {
+		int err = 0;
+		do {
+			if (addr->ss.sa_family == AF_INET) {
+				err = connect(fd, (const struct sockaddr *) addr, sizeof(struct sockaddr_in));
+			} else if (addr->ss.sa_family == AF_INET6) {
+				err = connect(fd, (const struct sockaddr *) addr, sizeof(struct sockaddr_in6));
+			} else {
+				return -1;
+			}
+		} while (err < 0 && errno == EINTR);
+
+		if(out_errno)
+		  *out_errno = errno;
+
+		if (err < 0 && errno != EINPROGRESS)
+			perror("Connect");
+
+		return err;
+	}
+}
+
+int addr_bind(evutil_socket_t fd, const ioa_addr* addr, int reusable)
+{
+	if (!addr || fd < 0) {
+
+		return -1;
+
+	} else {
+
+		int ret = -1;
+
+		socket_set_reusable(fd, reusable);
+
+		if (addr->ss.sa_family == AF_INET) {
+			do {
+				ret = bind(fd, (const struct sockaddr *) addr, sizeof(struct sockaddr_in));
+			} while (ret < 0 && errno == EINTR);
+		} else if (addr->ss.sa_family == AF_INET6) {
+			const int off = 0;
+			setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &off, sizeof(off));
+			do {
+				ret = bind(fd, (const struct sockaddr *) addr, sizeof(struct sockaddr_in6));
+			} while (ret < 0 && errno == EINTR);
+		} else {
+			return -1;
+		}
+		if(ret<0) {
+			int err = errno;
+			perror("bind");
+			char str[129];
+			addr_to_string(addr,(u08bits*)str);
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Trying to bind fd %d to <%s>: errno=%d\n", fd, str, err);
+		}
+		return ret;
+	}
+}
+
+int addr_get_from_sock(evutil_socket_t fd, ioa_addr *addr)
+{
+
+	if (fd < 0 || !addr)
+		return -1;
+	else {
+
+		ioa_addr a;
+		a.ss.sa_family = AF_INET6;
+		socklen_t socklen = get_ioa_addr_len(&a);
+		if (getsockname(fd, (struct sockaddr*) &a, &socklen) < 0) {
+			a.ss.sa_family = AF_INET;
+			socklen = get_ioa_addr_len(&a);
+			if (getsockname(fd, (struct sockaddr*) &a, &socklen) < 0) {
+				return -1;
+			}
+		}
+
+		addr_cpy(addr, &a);
+
+		return 0;
+	}
+}
+
+/////////////////// MTU /////////////////////////////////////////
+
+int set_socket_df(evutil_socket_t fd, int family, int value)
+{
+
+  int ret=0;
+
+#if defined(IP_DONTFRAG) && defined(IPPROTO_IP) //BSD
+  {
+    const int val=value;
+    /* kernel sets DF bit on outgoing IP packets */
+    if(family==AF_INET) {
+      ret = setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val));
+    } else {
+#if defined(IPV6_DONTFRAG) && defined(IPPROTO_IPV6)
+      ret = setsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG, &val, sizeof(val));
+#else
+#error CANNOT SET IPV6 SOCKET DF FLAG (1)
+#endif
+    }
+    if(ret<0) {
+      int err=errno;
+      perror("set socket df:");
+      TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s: set sockopt failed: fd=%d, err=%d, family=%d\n",__FUNCTION__,fd,err,family);
+    }
+  }
+#elif defined(IPPROTO_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) && defined(IP_PMTUDISC_DONT) //LINUX
+  {
+    /* kernel sets DF bit on outgoing IP packets */
+    if(family==AF_INET) {
+      int val=IP_PMTUDISC_DO;
+      if(!value) val=IP_PMTUDISC_DONT;
+      ret = setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));
+    } else {
+#if defined(IPPROTO_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) && defined(IPV6_PMTUDISC_DONT)
+      int val=IPV6_PMTUDISC_DO;
+      if(!value) val=IPV6_PMTUDISC_DONT;
+      ret = setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, sizeof(val));
+#else
+#error CANNOT SET IPV6 SOCKET DF FLAG (2)
+#endif
+    }
+    if(ret<0) {
+      perror("set DF");
+      TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s: set sockopt failed\n",__FUNCTION__);
+    }
+  }
+#else
+//CANNOT SET SOCKET DF FLAG (3) : UNKNOWN PLATFORM
+  UNUSED_ARG(fd);
+  UNUSED_ARG(family);
+  UNUSED_ARG(value);
+#endif
+
+  return ret;
+}
+
+static int get_mtu_from_ssl(SSL* ssl)
+{
+  int ret = SOSO_MTU;
+#if !defined(TURN_NO_DTLS)
+  if(ssl)
+	  ret = BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+#else
+  UNUSED_ARG(ssl);
+#endif
+  return ret;
+}
+
+static void set_query_mtu(SSL* ssl) {
+  if(ssl) {
+#if defined(SSL_OP_NO_QUERY_MTU)
+    SSL_set_options(ssl, SSL_OP_NO_QUERY_MTU);
+#else
+    ;
+#endif
+  }
+}
+
+int decrease_mtu(SSL* ssl, int mtu, int verbose)
+{
+
+	if (!ssl)
+		return mtu;
+
+	int new_mtu = get_mtu_from_ssl(ssl);
+
+	if (new_mtu < 1)
+		new_mtu = mtu;
+
+	if (new_mtu > MAX_MTU)
+		mtu = MAX_MTU;
+	if (new_mtu > 0 && new_mtu < MIN_MTU)
+		mtu = MIN_MTU;
+	else if (new_mtu < mtu)
+		mtu = new_mtu;
+	else
+		mtu -= MTU_STEP;
+
+	if (mtu < MIN_MTU)
+		mtu = MIN_MTU;
+
+	set_query_mtu(ssl);
+	if (verbose)
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "1. mtu to use: %d\n", mtu);
+
+#if !defined(TURN_NO_DTLS)
+	SSL_set_mtu(ssl,mtu);
+	BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_SET_MTU, mtu, NULL);
+#endif
+
+	return mtu;
+}
+
+int set_mtu_df(SSL* ssl, evutil_socket_t fd, int family, int mtu, int df_value, int verbose) {
+
+  if(!ssl || fd<0) return 0;
+
+  int ret=set_socket_df(fd, family, df_value);
+
+  if(!mtu) mtu=SOSO_MTU;
+  else if(mtu<MIN_MTU) mtu=MIN_MTU;
+  else if(mtu>MAX_MTU) mtu=MAX_MTU;
+
+  set_query_mtu(ssl);
+  if(verbose) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"3. mtu to use: %d\n",mtu);
+
+#if !defined(TURN_NO_DTLS)
+
+  SSL_set_mtu(ssl,mtu);
+
+  BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_SET_MTU, mtu, NULL);
+
+#endif
+
+  if(verbose) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"4. new mtu: %d\n",get_mtu_from_ssl(ssl));
+
+  return ret;
+}
+
+int get_socket_mtu(evutil_socket_t fd, int family, int verbose)
+{
+
+	int ret = 0;
+
+	UNUSED_ARG(fd);
+	UNUSED_ARG(family);
+	UNUSED_ARG(verbose);
+
+#if defined(IP_MTU)
+	int val = 0;
+	socklen_t slen=sizeof(val);
+	if(family==AF_INET) {
+		ret = getsockopt(fd, IPPROTO_IP, IP_MTU, &val, &slen);
+	} else {
+#if defined(IPPROTO_IPV6) && defined(IPV6_MTU)
+		ret = getsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &val, &slen);
+#endif
+		;
+	}
+
+	ret = val;
+#endif
+
+	if (verbose)
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: final=%d\n", __FUNCTION__, ret);
+
+	return ret;
+}
+
+//////////////////// socket error handle ////////////////////
+
+int handle_socket_error() {
+  switch (errno) {
+  case EINTR:
+    /* Interrupted system call.
+     * Just ignore.
+     */
+    return 1;
+  case ENOBUFS:
+    /* No buffers, temporary condition.
+     * Just ignore and try later.
+     */
+    return 1;
+  case EAGAIN:
+#if defined(EWOULDBLOCK)
+#if (EWOULDBLOCK != EAGAIN)
+  case EWOULDBLOCK:
+#endif
+#endif
+    return 1;
+  case EMSGSIZE:
+    return 1;
+  case EBADF:
+    /* Invalid socket.
+     * Must close connection.
+     */
+    return 0;
+  case EHOSTDOWN:
+    /* Host is down.
+     * Just ignore, might be an attacker
+     * sending fake ICMP messages.
+     */
+    return 1;
+  case ECONNRESET:
+  case ECONNREFUSED:
+    /* Connection reset by peer. */
+    return 0;
+  case ENOMEM:
+    /* Out of memory.
+     * Must close connection.
+     */
+    TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Out of memory!\n");
+    return 0;
+  case EACCES:
+    /* Permission denied.
+     * Just ignore, we might be blocked
+     * by some firewall policy. Try again
+     * and hope for the best.
+     */
+    return 1;
+  default:
+    /* Something unexpected happened */
+    TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Unexpected error! (errno = %d)\n", errno);
+    return 0;
+  }
+}
+
+//////////////////// Misc utils //////////////////////////////
+
+char *skip_blanks(char* s)
+{
+	while(*s==' ' || *s=='\t' || *s=='\n')
+		++s;
+
+	return s;
+}
+
+//////////////////// Config file search //////////////////////
+
+#define Q(x) #x
+#define QUOTE(x) Q(x)
+
+#define ETCDIR INSTALL_PREFIX/etc/
+#define QETCDIR QUOTE(ETCDIR)
+
+#define ETCDIR1 INSTALL_PREFIX/etc/turnserver/
+#define QETCDIR1 QUOTE(ETCDIR1)
+
+#define ETCDIR2 INSTALL_PREFIX/etc/coturn/
+#define QETCDIR2 QUOTE(ETCDIR2)
+
+static const char *config_file_search_dirs[] = {"./", "./turnserver/", "./coturn/", "./etc/", "./etc/turnserver/", "./etc/coturn/", "../etc/", "../etc/turnserver/", "../etc/coturn/", "/etc/", "/etc/turnserver/", "/etc/coturn/", "/usr/local/etc/", "/usr/local/etc/turnserver/", "/usr/local/etc/coturn/", QETCDIR, QETCDIR1, QETCDIR2, NULL };
+static char *c_execdir=NULL;
+
+void set_execdir(void)
+{
+  /* On some systems, this may give us the execution path */
+  char *_var = getenv("_");
+  if(_var && *_var) {
+    _var = strdup(_var);
+    char *edir=_var;
+    if(edir[0]!='.') 
+      edir = strstr(edir,"/");
+    if(edir && *edir)
+      edir = dirname(edir);
+    else
+      edir = dirname(_var);
+    if(c_execdir)
+      turn_free(c_execdir,strlen(c_execdir)+1);
+    c_execdir = strdup(edir);
+    turn_free(_var,strlen(_var)+1);
+  }
+}
+
+void print_abs_file_name(const char *msg1, const char *msg2, const char *fn) 
+{
+  char absfn[1025];
+  absfn[0]=0;
+
+  if(fn) {
+    while(fn[0] && fn[0]==' ') ++fn;
+    if(fn[0]) {
+      if(fn[0]=='/') {
+	STRCPY(absfn,fn);
+      } else {
+	if(fn[0]=='.' && fn[1]=='/')
+	  fn+=2;
+	if(!getcwd(absfn,sizeof(absfn)-1))
+	  absfn[0]=0;
+	size_t blen=strlen(absfn);
+	if(blen<sizeof(absfn)-1) {
+	  strncpy(absfn+blen,"/",sizeof(absfn)-blen);
+	  strncpy(absfn+blen+1,fn,sizeof(absfn)-blen-1);
+	} else {
+	  STRCPY(absfn,fn);
+	}
+	absfn[sizeof(absfn)-1]=0;
+      }
+    }
+  }
+  if(absfn[0]) {
+    TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s%s file found: %s\n", msg1, msg2, absfn);
+  }
+}
+
+char* find_config_file(const char *config_file, int print_file_name)
+{
+	char *full_path_to_config_file = NULL;
+
+	if (config_file && config_file[0]) {
+		if ((config_file[0] == '/')||(config_file[0] == '~')) {
+			FILE *f = fopen(config_file, "r");
+			if (f) {
+				fclose(f);
+				full_path_to_config_file = strdup(config_file);
+			}
+		} else {
+			int i = 0;
+			size_t cflen = strlen(config_file);
+
+			while (config_file_search_dirs[i]) {
+				size_t dirlen = strlen(config_file_search_dirs[i]);
+				size_t fnsz = sizeof(char) * (dirlen + cflen + 10);
+				char *fn = (char*)turn_malloc(fnsz+1);
+				strncpy(fn, config_file_search_dirs[i], fnsz);
+				strncpy(fn + dirlen, config_file, fnsz-dirlen);
+				fn[fnsz]=0;
+				FILE *f = fopen(fn, "r");
+				if (f) {
+					fclose(f);
+					if (print_file_name)
+					  print_abs_file_name("","Config",fn);
+					full_path_to_config_file = fn;
+					break;
+				}
+				turn_free(fn,fnsz+1);
+				if(config_file_search_dirs[i][0]!='/' && 
+				   config_file_search_dirs[i][0]!='.' &&
+				   c_execdir && c_execdir[0]) {
+					size_t celen = strlen(c_execdir);
+					fnsz = sizeof(char) * (dirlen + cflen + celen + 10);
+					fn = (char*)turn_malloc(fnsz+1);
+					strncpy(fn,c_execdir,fnsz);
+					size_t fnlen=strlen(fn);
+					if(fnlen<fnsz) {
+					  strncpy(fn+fnlen,"/",fnsz-fnlen);
+					  fnlen=strlen(fn);
+					  if(fnlen<fnsz) {
+					    strncpy(fn+fnlen, config_file_search_dirs[i], fnsz-fnlen);
+					    fnlen=strlen(fn);
+					    if(fnlen<fnsz) {
+					      strncpy(fn+fnlen, config_file, fnsz-fnlen);
+					    }
+					  }
+					}
+					fn[fnsz]=0;
+					if(strstr(fn,"//")!=fn) {
+					  f = fopen(fn, "r");
+					  if (f) {
+					    fclose(f);
+					    if (print_file_name)
+					      print_abs_file_name("","Config",fn);
+					    full_path_to_config_file = fn;
+					    break;
+					  }
+					}
+					turn_free(fn,fnsz+1);
+				}
+				++i;
+			}
+		}
+
+		if(!full_path_to_config_file) {
+			if(strstr(config_file,"etc/")==config_file) {
+				return find_config_file(config_file+4, print_file_name);
+			}
+		}
+	}
+
+	return full_path_to_config_file;
+}
+
+/////////////////// SYS SETTINGS ///////////////////////
+
+void ignore_sigpipe(void)
+{
+	/* Ignore SIGPIPE from TCP sockets */
+	if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+		perror("Cannot set SIGPIPE handler");
+	}
+}
+
+static u64bits turn_getRandTime(void) {
+  struct timespec tp={0,0};
+#if defined(CLOCK_REALTIME)
+  clock_gettime(CLOCK_REALTIME, &tp);
+#else
+  tp.tv_sec = time(NULL);
+#endif
+  u64bits current_time = (u64bits)(tp.tv_sec);
+  u64bits current_mstime = (u64bits)(current_time + (tp.tv_nsec));
+
+  return current_mstime;
+}
+
+unsigned long set_system_parameters(int max_resources)
+{
+	srandom((unsigned int) (turn_getRandTime() + (unsigned int)((long)(&turn_getRandTime))));
+	setlocale(LC_ALL, "C");
+
+	build_base64_decoding_table();
+
+	ignore_sigpipe();
+
+	if(max_resources) {
+		struct rlimit rlim;
+		if(getrlimit(RLIMIT_NOFILE, &rlim)<0) {
+			perror("Cannot get system limit");
+		} else {
+			rlim.rlim_cur = rlim.rlim_max;
+			while((setrlimit(RLIMIT_NOFILE, &rlim)<0) && (rlim.rlim_cur>0)) {
+				rlim.rlim_cur = rlim.rlim_cur>>1;
+			}
+			return (unsigned long)rlim.rlim_cur;
+		}
+	}
+
+	return 0;
+}
+
+////////////////////// Base 64 ////////////////////////////
+
+static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+                                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+                                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+                                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+                                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+                                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+                                'w', 'x', 'y', 'z', '0', '1', '2', '3',
+                                '4', '5', '6', '7', '8', '9', '+', '/'};
+static char *decoding_table = NULL;
+static size_t mod_table[] = {0, 2, 1};
+
+char *base64_encode(const unsigned char *data,
+                    size_t input_length,
+                    size_t *output_length) {
+
+    *output_length = 4 * ((input_length + 2) / 3);
+
+    char *encoded_data = (char*)turn_malloc(*output_length+1);
+    if (encoded_data == NULL) return NULL;
+
+    size_t i,j;
+    for (i = 0, j = 0; i < input_length;) {
+
+        u32bits octet_a = i < input_length ? data[i++] : 0;
+        u32bits octet_b = i < input_length ? data[i++] : 0;
+        u32bits octet_c = i < input_length ? data[i++] : 0;
+
+        u32bits triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
+
+        encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
+        encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
+        encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
+        encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
+    }
+
+    for (i = 0; i < mod_table[input_length % 3]; i++)
+        encoded_data[*output_length - 1 - i] = '=';
+
+    encoded_data[*output_length]=0;
+
+    return encoded_data;
+}
+
+void build_base64_decoding_table() {
+
+    decoding_table = (char*)turn_malloc(256);
+    ns_bzero(decoding_table,256);
+
+    int i;
+    for (i = 0; i < 64; i++)
+        decoding_table[(unsigned char) encoding_table[i]] = (char)i;
+}
+
+unsigned char *base64_decode(const char *data,
+                             size_t input_length,
+                             size_t *output_length) {
+
+    if (decoding_table == NULL) build_base64_decoding_table();
+
+    if (input_length % 4 != 0) return NULL;
+
+    *output_length = input_length / 4 * 3;
+    if (data[input_length - 1] == '=') (*output_length)--;
+    if (data[input_length - 2] == '=') (*output_length)--;
+
+    unsigned char *decoded_data = (unsigned char*)turn_malloc(*output_length);
+    if (decoded_data == NULL) return NULL;
+
+    int i;
+    size_t j;
+    for (i = 0, j = 0; i < (int)input_length;) {
+
+		uint32_t sextet_a =
+				data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
+		uint32_t sextet_b =
+				data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
+		uint32_t sextet_c =
+				data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
+		uint32_t sextet_d =
+				data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
+
+		uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6)
+				+ (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
+
+		if (j < *output_length)
+			decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
+		if (j < *output_length)
+			decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
+		if (j < *output_length)
+			decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
+
+    }
+
+    return decoded_data;
+}
+
+////////////////// SSL /////////////////////
+
+static const char* turn_get_method(const SSL_METHOD *method, const char* mdefault)
+{
+	{
+		if(!method)
+			return mdefault;
+		else {
+
+#ifndef OPENSSL_NO_SSL2
+			if(method == SSLv2_server_method()) {
+					return "SSLv2";
+			} else if(method == SSLv2_client_method()) {
+					return "SSLv2";
+			} else
+#endif
+
+			if(method == SSLv3_server_method()) {
+				return "SSLv3";
+			} else if(method == SSLv3_client_method()) {
+				return "SSLv3";
+			} else if(method == SSLv23_server_method()) {
+					return "SSLv23";
+			} else if(method == SSLv23_client_method()) {
+					return "SSLv23";
+			} else if(method == TLSv1_server_method()) {
+					return "TLSv1.0";
+			} else if(method == TLSv1_client_method()) {
+				return "TLSv1.0";
+#if defined(SSL_TXT_TLSV1_1)
+			} else if(method == TLSv1_1_server_method()) {
+					return "TLSv1.1";
+			} else if(method == TLSv1_1_client_method()) {
+				return "TLSv1.1";
+#if defined(SSL_TXT_TLSV1_2)
+			} else if(method == TLSv1_2_server_method()) {
+					return "TLSv1.2";
+			} else if(method == TLSv1_2_client_method()) {
+				return "TLSv1.2";
+#endif
+#endif
+#if !defined(TURN_NO_DTLS)
+			} else if(method == DTLSv1_server_method()) {
+					return "DTLSv1.0";
+			} else if(method == DTLSv1_client_method()) {
+				return "DTLSv1.0";
+#endif
+			} else {
+				if(mdefault)
+					return mdefault;
+				return "UNKNOWN";
+			}
+		}
+	}
+
+}
+
+const char* turn_get_ssl_method(SSL *ssl, const char* mdefault)
+{
+	if(!ssl)
+		return mdefault;
+	else {
+		const SSL_METHOD *method = SSL_get_ssl_method(ssl);
+		if(!method)
+			return mdefault;
+		else
+			return turn_get_method(method, mdefault);
+	}
+}
+
+//////////// EVENT BASE ///////////////
+
+struct event_base *turn_event_base_new(void)
+{
+	struct event_config *cfg = event_config_new();
+
+	event_config_set_flag(cfg,EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
+
+	return event_base_new_with_config(cfg);
+}
+
+//////////////////////////////////////////////////////////////

+ 163 - 0
src/apps/common/apputils.h

@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __APP_LIB__
+#define __APP_LIB__
+
+#include <event2/event.h>
+
+#include <openssl/ssl.h>
+
+#include "ns_turn_ioaddr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////// Common defines ///////////////////////////
+
+#define PEER_DEFAULT_PORT (3480)
+
+#define DTLS_MAX_RECV_TIMEOUT (5)
+
+#define UR_CLIENT_SOCK_BUF_SIZE (65536)
+#define UR_SERVER_SOCK_BUF_SIZE (UR_CLIENT_SOCK_BUF_SIZE * 32)
+
+extern int IS_TURN_SERVER;
+
+/////////// SSL //////////////////////////
+
+enum _TURN_TLS_TYPE {
+	TURN_TLS_NO=0,
+	TURN_TLS_SSL23,
+	TURN_TLS_v1_0,
+#if defined(SSL_TXT_TLSV1_1)
+	TURN_TLS_v1_1,
+#if defined(SSL_TXT_TLSV1_2)
+	TURN_TLS_v1_2,
+#endif
+#endif
+	TURN_TLS_TOTAL
+};
+
+typedef enum _TURN_TLS_TYPE TURN_TLS_TYPE;
+
+//////////////////////////////////////////
+
+#define EVENT_DEL(ev) if(ev) { event_del(ev); event_free(ev); ev=NULL; }
+
+//////////////////////////////////////////
+
+#define ioa_socket_raw int
+
+///////////////////////// Sockets ///////////////////////////////
+
+#if defined(WIN32)
+/** Do the platform-specific call needed to close a socket returned from
+    socket() or accept(). */
+#define socket_closesocket(s) closesocket(s)
+#else
+/** Do the platform-specific call needed to close a socket returned from
+    socket() or accept(). */
+#define socket_closesocket(s) close(s)
+#endif
+
+void read_spare_buffer(evutil_socket_t fd);
+
+int set_sock_buf_size(evutil_socket_t fd, int sz);
+
+int socket_set_reusable(evutil_socket_t fd, int reusable);
+int sock_bind_to_device(evutil_socket_t fd, const unsigned char* ifname);
+int socket_set_nonblocking(evutil_socket_t fd);
+int socket_tcp_set_keepalive(evutil_socket_t fd);
+
+int addr_connect(evutil_socket_t fd, const ioa_addr* addr, int *out_errno);
+
+int addr_bind(evutil_socket_t fd, const ioa_addr* addr, int reusable);
+
+int addr_get_from_sock(evutil_socket_t fd, ioa_addr *addr);
+
+int handle_socket_error(void);
+
+/////////////////////// SYS /////////////////////
+
+void ignore_sigpipe(void);
+unsigned long set_system_parameters(int max_resources);
+
+///////////////////////// MTU //////////////////////////
+
+#define MAX_MTU (1500 - 20 - 8)
+#define MIN_MTU (576 - 20 - 8)
+#define SOSO_MTU (1300)
+
+#define MTU_STEP (68)
+
+int set_socket_df(evutil_socket_t fd, int family, int value);
+int set_mtu_df(SSL* ssl, evutil_socket_t fd, int family, int mtu, int df_value, int verbose);
+int decrease_mtu(SSL* ssl, int mtu, int verbose);
+int get_socket_mtu(evutil_socket_t fd, int family, int verbose);
+
+////////////////// Misc utils /////////////////////////
+
+char *skip_blanks(char* s);
+
+////////////////// File search ////////////////////////
+
+char* find_config_file(const char *config_file, int print_file_name);
+void set_execdir(void);
+void print_abs_file_name(const char *msg1, const char *msg2, const char *fn);
+
+////////////////// Base64 /////////////////////////////
+
+char *base64_encode(const unsigned char *data,
+                    size_t input_length,
+                    size_t *output_length);
+
+void build_base64_decoding_table(void);
+
+unsigned char *base64_decode(const char *data,
+                             size_t input_length,
+                             size_t *output_length);
+
+///////////// SSL ////////////////
+
+const char* turn_get_ssl_method(SSL *ssl, const char* mdefault);
+
+//////////// Event Base /////////////////////
+
+struct event_base *turn_event_base_new(void);
+
+///////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__APP_LIB__

+ 383 - 0
src/apps/common/hiredis_libevent2.c

@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if !defined(TURN_NO_HIREDIS)
+
+#include "hiredis_libevent2.h"
+#include "ns_turn_utils.h"
+
+#include <event2/bufferevent.h>
+#include <event2/buffer.h>
+
+#include <hiredis/hiredis.h>
+#include <hiredis/async.h>
+
+//////////////// Libevent context ///////////////////////
+
+struct redisLibeventEvents
+{
+	redisAsyncContext *context;
+	int invalid;
+	int allocated;
+	struct event_base *base;
+	struct event *rev, *wev;
+	int rev_set, wev_set;
+	char *ip;
+	int port;
+	char *pwd;
+	int db;
+};
+
+///////////// Messages ////////////////////////////
+
+struct redis_message
+{
+	char format[513];
+	char arg[513];
+};
+
+/////////////////// forward declarations ///////////////
+
+static void redis_reconnect(struct redisLibeventEvents *e);
+
+//////////////////////////////////////////////////////////
+
+static int redis_le_valid(struct redisLibeventEvents *e)
+{
+	return (e && !(e->invalid) && (e->context));
+}
+
+/////////////////// Callbacks ////////////////////////////
+
+static void redisLibeventReadEvent(int fd, short event, void *arg) {
+  ((void)fd); ((void)event);
+  struct redisLibeventEvents *e = (struct redisLibeventEvents*)arg;
+  if(redis_le_valid(e)) {
+	  {
+		  char buf[8];
+		  int len = 0;
+		  do {
+			  len = recv(fd,buf,sizeof(buf),MSG_PEEK);
+		  } while((len<0)&&(errno == EINTR));
+		  if(len<1) {
+			  e->invalid = 1;
+			  TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Redis connection broken: e=0x%lx\n", __FUNCTION__, (unsigned long)e);
+		  }
+	  }
+	  if(redis_le_valid(e)) {
+		  redisAsyncHandleRead(e->context);
+	  }
+  }
+}
+
+static void redisLibeventWriteEvent(int fd, short event, void *arg) {
+  ((void)fd); ((void)event);
+  struct redisLibeventEvents *e = (struct redisLibeventEvents*)arg;
+  if(redis_le_valid(e)) {
+    redisAsyncHandleWrite(e->context);
+  }
+}
+
+static void redisLibeventAddRead(void *privdata) {
+  struct redisLibeventEvents *e = (struct redisLibeventEvents*)privdata;
+  if(e && (e->rev) && !(e->rev_set)) {
+    event_add(e->rev,NULL);
+    e->rev_set = 1;
+  }
+}
+
+static void redisLibeventDelRead(void *privdata) {
+    struct redisLibeventEvents *e = (struct redisLibeventEvents*)privdata;
+    if(e && e->rev && e->rev_set) {
+      event_del(e->rev);
+      e->rev_set = 0;
+    }
+}
+
+static void redisLibeventAddWrite(void *privdata) {
+    struct redisLibeventEvents *e = (struct redisLibeventEvents*)privdata;
+    if(e && (e->wev) && !(e->wev_set)) {
+      event_add(e->wev,NULL);
+      e->wev_set = 1;
+    }
+}
+
+static void redisLibeventDelWrite(void *privdata) {
+  struct redisLibeventEvents *e = (struct redisLibeventEvents*)privdata;
+  if(e && e->wev && e->wev_set) {
+    event_del(e->wev);
+    e->wev_set = 0;
+  }
+}
+
+static void redisLibeventCleanup(void *privdata)
+{
+
+	if (privdata) {
+
+		struct redisLibeventEvents *e = (struct redisLibeventEvents *) privdata;
+		if (e->allocated) {
+			if (e->rev) {
+				if(e->rev_set)
+					event_del(e->rev);
+				event_free(e->rev);
+				e->rev = NULL;
+			}
+			e->rev_set = 0;
+			if (e->wev) {
+				if(e->wev_set)
+					event_del(e->wev);
+				event_free(e->wev);
+				e->wev = NULL;
+			}
+			e->wev_set = 0;
+			e->context = NULL;
+		}
+	}
+}
+
+///////////////////////// Send-receive ///////////////////////////
+
+void redis_async_init(void)
+{
+	;
+}
+
+int is_redis_asyncconn_good(redis_context_handle rch)
+{
+	if(rch) {
+		struct redisLibeventEvents *e = (struct redisLibeventEvents*)rch;
+		if(redis_le_valid(e))
+			return 1;
+	}
+	return 0;
+}
+
+void send_message_to_redis(redis_context_handle rch, const char *command, const char *key, const char *format,...)
+{
+	if(!rch) {
+		return;
+	} else {
+
+		struct redisLibeventEvents *e = (struct redisLibeventEvents*)rch;
+
+		if(!redis_le_valid(e)) {
+			redis_reconnect(e);
+		}
+
+		if(!redis_le_valid(e)) {
+			;
+		} else {
+
+			redisAsyncContext *ac=e->context;
+
+			struct redis_message rm;
+
+			snprintf(rm.format,sizeof(rm.format)-3,"%s %s ", command, key);
+			strcpy(rm.format+strlen(rm.format),"%s");
+
+			va_list args;
+			va_start (args, format);
+			vsnprintf(rm.arg, sizeof(rm.arg)-1, format, args);
+			va_end (args);
+
+			if((redisAsyncCommand(ac, NULL, e, rm.format, rm.arg)!=REDIS_OK)) {
+				e->invalid = 1;
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Redis connection broken: ac=0x%lx, e=0x%x\n", __FUNCTION__,(unsigned long)ac,(unsigned long)e);
+			}
+		}
+	}
+}
+
+///////////////////////// Attach /////////////////////////////////
+
+redis_context_handle redisLibeventAttach(struct event_base *base, char *ip0, int port0, char *pwd, int db)
+{
+
+  struct redisLibeventEvents *e = NULL;
+  redisAsyncContext *ac = NULL;
+
+  char ip[256];
+  if(ip0 && ip0[0])
+	  STRCPY(ip,ip0);
+  else
+	  STRCPY(ip,"127.0.0.1");
+
+  int port = DEFAULT_REDIS_PORT;
+  if(port0>0)
+	  port=port0;
+
+  ac = redisAsyncConnect(ip, port);
+  if (!ac) {
+  	fprintf(stderr,"Error: %s:%s\n", ac->errstr, ac->c.errstr);
+  	return NULL;
+  }
+
+  /* Create container for context and r/w events */
+  e = (struct redisLibeventEvents*)turn_malloc(sizeof(struct redisLibeventEvents));
+  ns_bzero(e,sizeof(struct redisLibeventEvents));
+
+  e->allocated = 1;
+  e->context = ac;
+  e->base = base;
+  e->ip = strdup(ip);
+  e->port = port;
+  if(pwd)
+	  e->pwd = strdup(pwd);
+  e->db = db;
+
+  /* Register functions to start/stop listening for events */
+  ac->ev.addRead = redisLibeventAddRead;
+  ac->ev.delRead = redisLibeventDelRead;
+  ac->ev.addWrite = redisLibeventAddWrite;
+  ac->ev.delWrite = redisLibeventDelWrite;
+  ac->ev.cleanup = redisLibeventCleanup;
+
+  ac->ev.data = e;
+
+  /* Initialize and install read/write events */
+  e->rev = event_new(e->base,e->context->c.fd,
+  		     EV_READ,redisLibeventReadEvent,
+  		     e);
+
+  e->wev = event_new(e->base,e->context->c.fd,
+		     EV_WRITE,redisLibeventWriteEvent,
+  		     e);
+
+  if (e->rev == NULL || e->wev == NULL) {
+	  turn_free(e, sizeof(struct redisLibeventEvents));
+	  return NULL;
+  }
+  
+  event_add(e->wev, NULL);
+  e->wev_set = 1;
+
+  //Authentication
+  if(redis_le_valid(e) && pwd) {
+	  if(redisAsyncCommand(ac, NULL, e, "AUTH %s", pwd)!=REDIS_OK) {
+		  e->invalid = 1;
+	  }
+  }
+
+  if(redis_le_valid(e)) {
+	  if(redisAsyncCommand(ac, NULL, e, "SELECT %d", db)!=REDIS_OK) {
+		  e->invalid = 1;
+	  }
+  }
+
+  return (redis_context_handle)e;
+}
+
+static void redis_reconnect(struct redisLibeventEvents *e)
+{
+  if(!e || !(e->allocated))
+	  return;
+
+  if (e->rev) {
+  	if(e->rev_set)
+  		event_del(e->rev);
+  	event_free(e->rev);
+  	e->rev = NULL;
+  }
+  e->rev_set = 0;
+
+  if (e->wev) {
+  	if(e->wev_set)
+  		event_del(e->wev);
+  	event_free(e->wev);
+  	e->wev = NULL;
+  }
+  e->wev_set = 0;
+
+  redisAsyncContext *ac = NULL;
+
+  if(e->context) {
+	  e->context = NULL;
+  }
+
+  ac = redisAsyncConnect(e->ip, e->port);
+  if(!ac) {
+	  return;
+  }
+
+  e->context = ac;
+
+ /* Register functions to start/stop listening for events */
+  ac->ev.addRead = redisLibeventAddRead;
+  ac->ev.delRead = redisLibeventDelRead;
+  ac->ev.addWrite = redisLibeventAddWrite;
+  ac->ev.delWrite = redisLibeventDelWrite;
+  ac->ev.cleanup = redisLibeventCleanup;
+
+  ac->ev.data = e;
+
+  /* Initialize and install read/write events */
+  e->rev = event_new(e->base,e->context->c.fd,
+  		     EV_READ,redisLibeventReadEvent,
+  		     e);
+
+  e->wev = event_new(e->base,e->context->c.fd,
+		     EV_WRITE,redisLibeventWriteEvent,
+  		     e);
+
+  if (e->rev == NULL || e->wev == NULL) {
+	  return;
+  }
+
+  event_add(e->wev, NULL);
+  e->wev_set = 1;
+  e->invalid = 0;
+
+  //Authentication
+  if(redis_le_valid(e) && e->pwd) {
+	  if(redisAsyncCommand(ac, NULL, e, "AUTH %s", e->pwd)!=REDIS_OK) {
+		  e->invalid = 1;
+	  }
+  }
+
+  if(redis_le_valid(e)) {
+	  if(redisAsyncCommand(ac, NULL, e, "SELECT %d", e->db)!=REDIS_OK) {
+		  e->invalid = 1;
+	  }
+  }
+
+  if(redis_le_valid(e)) {
+	  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Re-connected to redis, async\n", __FUNCTION__);
+  }
+}
+
+/////////////////////////////////////////////////////////
+
+#endif
+/* TURN_NO_HIREDIS */
+

+ 67 - 0
src/apps/common/hiredis_libevent2.h

@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __HIREDIS_LIBEVENT_H__
+
+#define __HIREDIS_LIBEVENT_H__
+
+#if !defined(TURN_NO_HIREDIS)
+
+#include <event2/event.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////////////////////
+
+#define DEFAULT_REDIS_PORT (6379)
+
+typedef void* redis_context_handle;
+
+//////////////////////////////////////
+
+void redis_async_init(void);
+
+redis_context_handle redisLibeventAttach(struct event_base *base, char *ip, int port, char *pwd, int db);
+
+void send_message_to_redis(redis_context_handle rch, const char *command, const char *key, const char *format,...);
+
+int is_redis_asyncconn_good(redis_context_handle rch);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* TURN_NO_HIREDIS */
+
+#endif
+/*__HIREDIS_LIBEVENT_H__*/

+ 643 - 0
src/apps/common/ns_turn_utils.c

@@ -0,0 +1,643 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "ns_turn_utils.h"
+#include "ns_turn_ioalib.h"
+#include "ns_turn_msg_defs.h"
+
+#include <time.h>
+
+#include <pthread.h>
+
+#include <syslog.h>
+#include <stdarg.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+////////// LOG TIME OPTIMIZATION ///////////
+
+static volatile turn_time_t log_start_time = 0;
+volatile int _log_time_value_set = 0;
+volatile turn_time_t _log_time_value = 0;
+
+static inline turn_time_t log_time(void)
+{
+  if(!log_start_time)
+    log_start_time = turn_time();
+
+  if(_log_time_value_set)
+    return (_log_time_value - log_start_time);
+
+  return (turn_time() - log_start_time);
+}
+
+////////// MUTEXES /////////////
+
+#define MAGIC_CODE (0xEFCD1983)
+
+int turn_mutex_lock(const turn_mutex *mutex) {
+  if(mutex && mutex->mutex && (mutex->data == MAGIC_CODE)) {
+    int ret = 0;
+    ret = pthread_mutex_lock((pthread_mutex_t*)mutex->mutex);
+    if(ret<0) {
+      perror("Mutex lock");
+    }
+    return ret;
+  } else {
+    printf("Uninitialized mutex\n");
+    return -1;
+  }
+}
+
+int turn_mutex_unlock(const turn_mutex *mutex) {
+  if(mutex && mutex->mutex && (mutex->data == MAGIC_CODE)) {
+    int ret = 0;
+    ret = pthread_mutex_unlock((pthread_mutex_t*)mutex->mutex);
+    if(ret<0) {
+      perror("Mutex unlock");
+    }
+    return ret;
+  } else {
+    printf("Uninitialized mutex\n");
+    return -1;
+  }
+}
+
+int turn_mutex_init(turn_mutex* mutex) {
+  if(mutex) {
+    mutex->data=MAGIC_CODE;
+    mutex->mutex=turn_malloc(sizeof(pthread_mutex_t));
+    pthread_mutex_init((pthread_mutex_t*)mutex->mutex,NULL);
+    return 0;
+  } else {
+    return -1;
+  }
+}
+
+int turn_mutex_init_recursive(turn_mutex* mutex) {
+	int ret = -1;
+	if (mutex) {
+		pthread_mutexattr_t attr;
+		if (pthread_mutexattr_init(&attr) < 0) {
+			perror("Cannot init mutex attr");
+		} else {
+			if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) < 0) {
+				perror("Cannot set type on mutex attr");
+			} else {
+				mutex->mutex = turn_malloc(sizeof(pthread_mutex_t));
+				mutex->data = MAGIC_CODE;
+				if ((ret = pthread_mutex_init((pthread_mutex_t*) mutex->mutex,
+						&attr)) < 0) {
+					perror("Cannot init mutex");
+					mutex->data = 0;
+					turn_free(mutex->mutex,sizeof(pthread_mutex_t));
+					mutex->mutex = NULL;
+				}
+			}
+			pthread_mutexattr_destroy(&attr);
+		}
+	}
+  return ret;
+}
+
+int turn_mutex_destroy(turn_mutex* mutex) {
+  if(mutex && mutex->mutex && mutex->data == MAGIC_CODE) {
+    int ret = 0;
+    ret = pthread_mutex_destroy((pthread_mutex_t*)(mutex->mutex));
+    turn_free(mutex->mutex, sizeof(pthread_mutex_t));
+    mutex->mutex=NULL;
+    mutex->data=0;
+    return ret;
+  } else {
+    return 0;
+  }
+}
+
+///////////////////////// LOG ///////////////////////////////////
+
+#if defined(TURN_LOG_FUNC_IMPL)
+extern void TURN_LOG_FUNC_IMPL(TURN_LOG_LEVEL level, const s08bits* format, va_list args);
+#endif
+
+static int no_stdout_log = 0;
+
+void set_no_stdout_log(int val)
+{
+	no_stdout_log = val;
+}
+
+void turn_log_func_default(TURN_LOG_LEVEL level, const s08bits* format, ...)
+{
+#if !defined(TURN_LOG_FUNC_IMPL)
+	{
+		va_list args;
+		va_start(args,format);
+		vrtpprintf(level, format, args);
+		va_end(args);
+	}
+#endif
+
+	{
+		va_list args;
+		va_start(args,format);
+#if defined(TURN_LOG_FUNC_IMPL)
+		TURN_LOG_FUNC_IMPL(level,format,args);
+#else
+#define MAX_RTPPRINTF_BUFFER_SIZE (1024)
+		char s[MAX_RTPPRINTF_BUFFER_SIZE+1];
+#undef MAX_RTPPRINTF_BUFFER_SIZE
+		if (level == TURN_LOG_LEVEL_ERROR) {
+			snprintf(s,sizeof(s)-100,"%lu: ERROR: ",(unsigned long)log_time());
+			size_t slen = strlen(s);
+			vsnprintf(s+slen,sizeof(s)-slen-1,format, args);
+			fwrite(s,strlen(s),1,stdout);
+		} else if(!no_stdout_log) {
+			snprintf(s,sizeof(s)-100,"%lu: ",(unsigned long)log_time());
+			size_t slen = strlen(s);
+			vsnprintf(s+slen,sizeof(s)-slen-1,format, args);
+			fwrite(s,strlen(s),1,stdout);
+		}
+#endif
+		va_end(args);
+	}
+}
+
+void addr_debug_print(int verbose, const ioa_addr *addr, const s08bits* s)
+{
+	if (verbose) {
+		if (!addr) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: EMPTY\n", s);
+		} else {
+			s08bits addrbuf[INET6_ADDRSTRLEN];
+			if (!s)
+				s = "";
+			if (addr->ss.sa_family == AF_INET) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "IPv4. %s: %s:%d\n", s, inet_ntop(AF_INET,
+								&addr->s4.sin_addr, addrbuf, INET6_ADDRSTRLEN),
+								nswap16(addr->s4.sin_port));
+			} else if (addr->ss.sa_family == AF_INET6) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "IPv6. %s: %s:%d\n", s, inet_ntop(AF_INET6,
+								&addr->s6.sin6_addr, addrbuf, INET6_ADDRSTRLEN),
+								nswap16(addr->s6.sin6_port));
+			} else {
+				if (addr_any_no_port(addr)) {
+					TURN_LOG_FUNC(
+									TURN_LOG_LEVEL_INFO,
+									"IP. %s: 0.0.0.0:%d\n",
+									s,
+									nswap16(addr->s4.sin_port));
+				} else {
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: wrong IP address family: %d\n", s,
+									(int) (addr->ss.sa_family));
+				}
+			}
+		}
+	}
+}
+
+/*************************************/
+
+#define FILE_STR_LEN (1025)
+
+static FILE* _rtpfile = NULL;
+static int to_syslog = 0;
+static int simple_log = 0;
+static char log_fn[FILE_STR_LEN]="\0";
+static char log_fn_base[FILE_STR_LEN]="\0";
+
+static turn_mutex log_mutex;
+static int log_mutex_inited = 0;
+
+static void log_lock(void) {
+	if(!log_mutex_inited) {
+		log_mutex_inited=1;
+		turn_mutex_init_recursive(&log_mutex);
+	}
+	turn_mutex_lock(&log_mutex);
+}
+
+static void log_unlock(void) {
+	turn_mutex_unlock(&log_mutex);
+}
+
+static void get_date(char *s, size_t sz) {
+	time_t curtm;
+    struct tm* tm_info;
+
+    curtm = time(NULL);
+    tm_info = localtime(&curtm);
+
+    strftime(s, sz, "%F", tm_info);
+}
+
+void set_logfile(const char *fn)
+{
+	if(fn) {
+		log_lock();
+		if(strcmp(fn,log_fn_base)) {
+			reset_rtpprintf();
+			STRCPY(log_fn_base,fn);
+		}
+		log_unlock();
+	}
+}
+
+void reset_rtpprintf(void)
+{
+	log_lock();
+	if(_rtpfile) {
+		if(_rtpfile != stdout)
+			fclose(_rtpfile);
+		_rtpfile = NULL;
+	}
+	log_unlock();
+}
+
+static void set_log_file_name(char *base, char *f)
+{
+	if(simple_log) {
+		STRCPY(f,base);
+		return;
+	}
+
+	char logdate[125];
+	char *tail=strdup(".log");
+
+	get_date(logdate,sizeof(logdate));
+
+	char *base1=strdup(base);
+
+	int len=(int)strlen(base1);
+
+	--len;
+
+	while(len>=0) {
+		if((base1[len]==' ')||(base1[len]=='\t')) {
+			base1[len]='_';
+		}
+		--len;
+	}
+
+	len=(int)strlen(base1);
+
+	while(len>=0) {
+		if(base1[len]=='/')
+			break;
+		else if(base1[len]=='.') {
+			turn_free(tail,strlen(tail)+1);
+			tail=strdup(base1+len);
+			base1[len]=0;
+			if(strlen(tail)<2) {
+				turn_free(tail,strlen(tail)+1);
+				tail = strdup(".log");
+			}
+			break;
+		}
+		--len;
+	}
+
+	len=(int)strlen(base1);
+	if(len>0 && (base1[len-1]!='/') && (base1[len-1]!='-') && (base1[len-1]!='_')) {
+	  snprintf(f, FILE_STR_LEN, "%s_%s%s", base1,logdate,tail);
+	} else {
+	  snprintf(f, FILE_STR_LEN, "%s%s%s", base1,logdate,tail);
+	}
+
+	turn_free(base1,strlen(base1)+1);
+	turn_free(tail,strlen(tail)+1);
+}
+
+static void set_rtpfile(void)
+{
+	if(to_syslog) {
+		return;
+	} else if (!_rtpfile) {
+		if(log_fn_base[0]) {
+			if(!strcmp(log_fn_base,"syslog")) {
+				_rtpfile = stdout;
+				to_syslog = 1;
+			} else if(!strcmp(log_fn_base,"stdout")|| !strcmp(log_fn_base,"-")) {
+				_rtpfile = stdout;
+				no_stdout_log = 1;
+			} else {
+				set_log_file_name(log_fn_base,log_fn);
+				_rtpfile = fopen(log_fn, "w");
+				if(_rtpfile)
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", log_fn);
+			}
+			if (!_rtpfile) {
+				fprintf(stderr,"ERROR: Cannot open log file for writing: %s\n",log_fn);
+			} else {
+				return;
+			}
+		}
+	}
+
+	if(!_rtpfile) {
+
+		char logbase[FILE_STR_LEN];
+		char logtail[FILE_STR_LEN];
+		char logf[FILE_STR_LEN];
+
+		if(simple_log)
+			snprintf(logtail, FILE_STR_LEN, "turn.log");
+		else
+			snprintf(logtail, FILE_STR_LEN, "turn_%d_", (int)getpid());
+
+		snprintf(logbase, FILE_STR_LEN, "/var/log/turnserver/%s", logtail);
+
+		set_log_file_name(logbase, logf);
+
+		_rtpfile = fopen(logf, "w");
+		if(_rtpfile)
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", logf);
+		else {
+			snprintf(logbase, FILE_STR_LEN, "/var/log/%s", logtail);
+
+			set_log_file_name(logbase, logf);
+			_rtpfile = fopen(logf, "w");
+			if(_rtpfile)
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", logf);
+			else {
+				snprintf(logbase, FILE_STR_LEN, "/var/tmp/%s", logtail);
+				set_log_file_name(logbase, logf);
+				_rtpfile = fopen(logf, "w");
+				if(_rtpfile)
+					TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", logf);
+				else {
+					snprintf(logbase, FILE_STR_LEN, "/tmp/%s", logtail);
+					set_log_file_name(logbase, logf);
+					_rtpfile = fopen(logf, "w");
+					if(_rtpfile)
+						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", logf);
+					else {
+						snprintf(logbase, FILE_STR_LEN, "%s", logtail);
+						set_log_file_name(logbase, logf);
+						_rtpfile = fopen(logf, "w");
+						if(_rtpfile)
+							TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", logf);
+						else {
+							_rtpfile = stdout;
+							return;
+						}
+					}
+				}
+			}
+		}
+
+		STRCPY(log_fn_base,logbase);
+		STRCPY(log_fn,logf);
+	}
+}
+
+void set_log_to_syslog(int val)
+{
+	to_syslog = val;
+}
+
+void set_simple_log(int val)
+{
+	simple_log = val;
+}
+
+#define Q(x) #x
+#define QUOTE(x) Q(x)
+
+void rollover_logfile(void)
+{
+	if(to_syslog || !(log_fn[0]))
+		return;
+
+	{
+		FILE *f = fopen(log_fn,"r");
+		if(!f) {
+			fprintf(stderr, "log file is damaged\n");
+			reset_rtpprintf();
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file reopened: %s\n", log_fn);
+			return;
+		} else {
+			fclose(f);
+		}
+	}
+
+	if(simple_log)
+		return;
+
+	log_lock();
+	if(_rtpfile && log_fn[0] && (_rtpfile != stdout)) {
+		char logf[FILE_STR_LEN];
+
+		set_log_file_name(log_fn_base,logf);
+		if(strcmp(log_fn,logf)) {
+			fclose(_rtpfile);
+			log_fn[0]=0;
+			_rtpfile = fopen(logf, "w");
+			if(_rtpfile) {
+				STRCPY(log_fn,logf);
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", log_fn);
+			} else {
+				_rtpfile = stdout;
+			}
+		}
+	}
+	log_unlock();
+}
+
+static int get_syslog_level(TURN_LOG_LEVEL level)
+{
+	switch(level) {
+	case TURN_LOG_LEVEL_CONTROL:
+		return LOG_NOTICE;
+	case TURN_LOG_LEVEL_WARNING:
+		return LOG_WARNING;
+	case TURN_LOG_LEVEL_ERROR:
+		return LOG_ERR;
+	default:
+		;
+	};
+	return LOG_INFO;
+}
+
+int vrtpprintf(TURN_LOG_LEVEL level, const char *format, va_list args)
+{
+	/* Fix for Issue 24, raised by John Selbie: */
+#define MAX_RTPPRINTF_BUFFER_SIZE (1024)
+	char s[MAX_RTPPRINTF_BUFFER_SIZE+1];
+#undef MAX_RTPPRINTF_BUFFER_SIZE
+
+	size_t sz;
+
+	snprintf(s, sizeof(s), "%lu: ",(unsigned long)log_time());
+	sz=strlen(s);
+	vsnprintf(s+sz, sizeof(s)-1-sz, format, args);
+	s[sizeof(s)-1]=0;
+
+	if(to_syslog) {
+		syslog(get_syslog_level(level),"%s",s);
+	} else {
+		log_lock();
+		set_rtpfile();
+		if(fprintf(_rtpfile,"%s",s)<0) {
+			reset_rtpprintf();
+		} else if(fflush(_rtpfile)<0) {
+			reset_rtpprintf();
+		}
+		log_unlock();
+	}
+
+	return 0;
+}
+
+void rtpprintf(const char *format, ...)
+{
+	va_list args;
+	va_start (args, format);
+	vrtpprintf(TURN_LOG_LEVEL_INFO, format, args);
+	va_end (args);
+}
+
+///////////// ORIGIN ///////////////////
+
+int get_default_protocol_port(const char* scheme, size_t slen)
+{
+	if(scheme && (slen>0)) {
+		switch(slen) {
+		case 3:
+			if(!memcmp("ftp",scheme,3))
+				return 21;
+			if(!memcmp("svn",scheme,3))
+				return 3690;
+			if(!memcmp("ssh",scheme,4))
+				return 22;
+			if(!memcmp("sip",scheme,3))
+				return 5060;
+			break;
+		case 4:
+			if(!memcmp("http",scheme,4))
+				return 80;
+			if(!memcmp("ldap",scheme,4))
+				return 389;
+			if(!memcmp("sips",scheme,4))
+				return 5061;
+			if(!memcmp("turn",scheme,4))
+				return 3478;
+			if(!memcmp("stun",scheme,4))
+				return 3478;
+			break;
+		case 5:
+			if(!memcmp("https",scheme,5))
+				return 443;
+			if(!memcmp("ldaps",scheme,5))
+				return 636;
+			if(!memcmp("turns",scheme,5))
+				return 5349;
+			if(!memcmp("stuns",scheme,5))
+				return 5349;
+			break;
+		case 6:
+			if(!memcmp("telnet",scheme,6))
+				return 23;
+			if(!memcmp("radius",scheme,6))
+				return 1645;
+			break;
+		case 7:
+			if(!memcmp("svn+ssh",scheme,7))
+				return 22;
+			break;
+		default:
+			return 0;
+		};
+	}
+	return 0;
+}
+
+int get_canonic_origin(const char* o, char *co, int sz)
+{
+	int ret = -1;
+
+	if(o && o[0] && co) {
+		co[0]=0;
+		struct evhttp_uri *uri = evhttp_uri_parse(o);
+		if(uri) {
+			const char *scheme = evhttp_uri_get_scheme(uri);
+			if(scheme && scheme[0]) {
+				size_t schlen = strlen(scheme);
+				if((schlen<(size_t)sz) && (schlen<STUN_MAX_ORIGIN_SIZE)) {
+					const char *host = evhttp_uri_get_host(uri);
+					if(host && host[0]) {
+						char otmp[STUN_MAX_ORIGIN_SIZE+STUN_MAX_ORIGIN_SIZE];
+						ns_bcopy(scheme,otmp,schlen);
+						otmp[schlen]=0;
+
+						{
+							char *s = otmp;
+							while(*s) {
+								*s = (char)tolower(*s);
+								++s;
+							}
+						}
+
+						int port = evhttp_uri_get_port(uri);
+						if(port<1) {
+							port = get_default_protocol_port(otmp, schlen);
+						}
+						if(port>0)
+							snprintf(otmp+schlen,sizeof(otmp)-schlen-1,"://%s:%d",host,port);
+						else
+							snprintf(otmp+schlen,sizeof(otmp)-schlen-1,"://%s",host);
+
+						{
+							char *s = otmp + schlen + 3;
+							while(*s) {
+								*s = (char)tolower(*s);
+								++s;
+							}
+						}
+
+						strncpy(co,otmp,sz);
+						co[sz]=0;
+						ret = 0;
+					}
+				}
+			}
+			evhttp_uri_free(uri);
+		}
+	}
+
+	if(ret<0) {
+		strncpy(co,o,sz);
+		co[sz]=0;
+	}
+
+	return ret;
+}
+
+//////////////////////////////////////////////////////////////////

+ 86 - 0
src/apps/common/ns_turn_utils.h

@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __TURN_ULIB__
+#define __TURN_ULIB__
+
+#if !defined(TURN_LOG_FUNC)
+#define TURN_LOG_FUNC turn_log_func_default
+#endif
+
+#include "ns_turn_ioaddr.h"
+
+#include <event2/http.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////// LOG //////////////////////////
+
+typedef enum {
+  TURN_LOG_LEVEL_INFO = 0,
+  TURN_LOG_LEVEL_CONTROL,
+  TURN_LOG_LEVEL_WARNING,
+  TURN_LOG_LEVEL_ERROR
+} TURN_LOG_LEVEL;
+
+#define TURN_VERBOSE_NONE (0)
+#define TURN_VERBOSE_NORMAL (1)
+#define TURN_VERBOSE_EXTRA (2)
+
+#define eve(v) ((v)==TURN_VERBOSE_EXTRA)
+
+void set_no_stdout_log(int val);
+void set_log_to_syslog(int val);
+void set_simple_log(int val);
+
+void turn_log_func_default(TURN_LOG_LEVEL level, const s08bits* format, ...);
+
+void addr_debug_print(int verbose, const ioa_addr *addr, const s08bits* s);
+
+/* Log */
+
+extern volatile int _log_time_value_set;
+extern volatile turn_time_t _log_time_value;
+
+void rtpprintf(const char *format, ...);
+int vrtpprintf(TURN_LOG_LEVEL level, const char *format, va_list args);
+void reset_rtpprintf(void);
+void set_logfile(const char *fn);
+void rollover_logfile(void);
+
+///////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__TURN_ULIB__

+ 252 - 0
src/apps/common/stun_buffer.c

@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "stun_buffer.h"
+
+////////////////////// BUFFERS ///////////////////////////
+
+int stun_init_buffer(stun_buffer *buf) {
+  if(!buf) return -1;
+  ns_bzero(buf->buf,sizeof(buf->buf));
+  buf->len=0;
+  buf->offset=0;
+  buf->coffset=0;
+  return 0;
+}
+
+int stun_get_size(const stun_buffer *buf) {
+  if(!buf) return 0;
+  return sizeof(buf->buf);
+}
+
+////////////////////////////////////////////////////////////
+
+void stun_tid_from_message(const stun_buffer *buf, stun_tid* id) {
+  stun_tid_from_message_str(buf->buf,(size_t)(buf->len), id);
+}
+
+void stun_tid_generate_in_message(stun_buffer* buf, stun_tid* id) {
+  if(buf) {
+    stun_tid_generate_in_message_str(buf->buf, id);
+  }
+}
+
+////////////////////////////////////////////////////////
+
+static inline int is_channel_msg(const stun_buffer* buf) {
+  if(buf && buf->len>0) {
+    return is_channel_msg_str(buf->buf, (size_t)(buf->len));
+  }
+  return 0;
+}
+
+int stun_is_command_message(const stun_buffer* buf) {
+  if(!buf || buf->len<=0)
+    return 0;
+  else
+    return stun_is_command_message_str(buf->buf,(size_t)(buf->len));
+}
+
+int stun_is_request(const stun_buffer* buf) {
+  return stun_is_request_str(buf->buf,(size_t)buf->len);
+}
+
+int stun_is_success_response(const stun_buffer* buf) {
+  return stun_is_success_response_str(buf->buf, (size_t)(buf->len));
+}
+
+int stun_is_error_response(const stun_buffer* buf, int *err_code, u08bits *err_msg, size_t err_msg_size) {
+  return stun_is_error_response_str(buf->buf, (size_t)(buf->len), err_code, err_msg, err_msg_size);
+}
+
+int stun_is_response(const stun_buffer* buf) {
+  return stun_is_response_str(buf->buf,(size_t)(buf->len));
+}
+
+int stun_is_indication(const stun_buffer* buf) {
+  if(is_channel_msg(buf)) return 0;
+  return IS_STUN_INDICATION(stun_get_msg_type(buf));
+}
+
+u16bits stun_get_method(const stun_buffer* buf) {
+	return stun_get_method_str(buf->buf, (size_t)(buf->len));
+}
+
+u16bits stun_get_msg_type(const stun_buffer* buf) {
+  if(!buf) return (u16bits)-1;
+  return stun_get_msg_type_str(buf->buf,(size_t)buf->len);
+}
+
+////////////////////////////////////////////////////////////
+
+static void stun_init_command(u16bits message_type, stun_buffer* buf) {
+  buf->len=stun_get_size(buf);
+  stun_init_command_str(message_type, buf->buf, (size_t*)(&(buf->len)));
+}
+
+void stun_init_request(u16bits method, stun_buffer* buf) {
+  stun_init_command(stun_make_request(method), buf);
+}
+
+void stun_init_indication(u16bits method, stun_buffer* buf) {
+  stun_init_command(stun_make_indication(method), buf);
+}
+
+void stun_init_success_response(u16bits method, stun_buffer* buf, stun_tid* id) {
+  buf->len=stun_get_size(buf);
+  stun_init_success_response_str(method, buf->buf, (size_t*)(&(buf->len)), id);
+}
+
+void stun_init_error_response(u16bits method, stun_buffer* buf, u16bits error_code, const u08bits *reason, stun_tid* id) {
+  buf->len=stun_get_size(buf);
+  stun_init_error_response_str(method, buf->buf, (size_t*)(&(buf->len)), error_code, reason, id);
+}
+ 
+///////////////////////////////////////////////////////////////////////////////
+
+int stun_get_command_message_len(const stun_buffer* buf) {
+  return stun_get_command_message_len_str(buf->buf, (size_t)(buf->len));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int stun_init_channel_message(u16bits chnumber, stun_buffer* buf, int length, int do_padding) {
+  return stun_init_channel_message_str(chnumber, buf->buf, (size_t*)(&(buf->len)), length, do_padding);
+}
+
+int stun_is_channel_message(stun_buffer* buf, u16bits* chnumber, int is_padding_mandatory) {
+  if(!buf) return 0;
+  size_t blen = (size_t)buf->len;
+  int ret = stun_is_channel_message_str(buf->buf, &blen, chnumber, is_padding_mandatory);
+  if(ret) {
+	  buf->len=(ssize_t)blen;
+  }
+  return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int stun_set_allocate_request(stun_buffer* buf, u32bits lifetime, int address_family, u08bits transport, int mobile) {
+  return stun_set_allocate_request_str(buf->buf, (size_t*)(&(buf->len)), lifetime, address_family, transport, mobile);
+}
+
+int stun_set_allocate_response(stun_buffer* buf, stun_tid* tid, 
+			       const ioa_addr *relayed_addr, const ioa_addr *reflexive_addr,
+			       u32bits lifetime, int error_code, const u08bits *reason,
+			       u64bits reservation_token, char *mobile_id) {
+
+  return stun_set_allocate_response_str(buf->buf, (size_t*)(&(buf->len)), tid, 
+					relayed_addr, reflexive_addr, 
+					lifetime, error_code, reason,
+					reservation_token, mobile_id);
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+u16bits stun_set_channel_bind_request(stun_buffer* buf, 
+				       const ioa_addr* peer_addr, u16bits channel_number) {
+
+  return stun_set_channel_bind_request_str(buf->buf,(size_t*)(&(buf->len)), peer_addr, channel_number);
+}
+
+void stun_set_channel_bind_response(stun_buffer* buf, stun_tid* tid, int error_code, const u08bits *reason) {
+  stun_set_channel_bind_response_str(buf->buf, (size_t*)(&(buf->len)), tid, error_code, reason);
+}
+
+////////////////////////////////////////////////////////////////
+
+stun_attr_ref stun_attr_get_first(const stun_buffer* buf) {
+  return stun_attr_get_first_str(buf->buf, (size_t)(buf->len));
+}
+
+stun_attr_ref stun_attr_get_next(const stun_buffer* buf, stun_attr_ref prev) {
+  return stun_attr_get_next_str(buf->buf, (size_t)(buf->len), prev);
+}
+
+int stun_attr_add(stun_buffer* buf, u16bits attr, const s08bits* avalue, int alen) {
+  return stun_attr_add_str(buf->buf, (size_t*)(&(buf->len)), attr, (const u08bits *)avalue, alen);
+}
+
+int stun_attr_add_channel_number(stun_buffer* buf, u16bits chnumber) {
+  return stun_attr_add_channel_number_str(buf->buf, (size_t *)(&(buf->len)), chnumber);
+}
+
+int stun_attr_add_addr(stun_buffer *buf,u16bits attr_type, const ioa_addr* ca) {
+  return stun_attr_add_addr_str(buf->buf,(size_t*)(&(buf->len)), attr_type, ca);
+}
+
+int stun_attr_get_addr(const stun_buffer *buf, stun_attr_ref attr, ioa_addr* ca, 
+		       const ioa_addr *default_addr) {
+
+  return stun_attr_get_addr_str(buf->buf, (size_t)(buf->len), attr, ca, default_addr);
+}
+
+int stun_attr_get_first_addr(const stun_buffer *buf, u16bits attr_type, ioa_addr* ca, 
+			     const ioa_addr *default_addr) {
+
+  return stun_attr_get_first_addr_str(buf->buf, (size_t)(buf->len), attr_type, ca, default_addr);
+}
+
+int stun_attr_add_even_port(stun_buffer* buf, uint8_t value) {
+  if(value) value=0x80;
+  return stun_attr_add(buf,STUN_ATTRIBUTE_EVEN_PORT,(const s08bits*)&value,1);
+}
+
+u16bits stun_attr_get_first_channel_number(const stun_buffer *buf) {
+  return stun_attr_get_first_channel_number_str(buf->buf, (size_t)(buf->len));
+}
+
+stun_attr_ref stun_attr_get_first_by_type(const stun_buffer* buf, u16bits attr_type) {
+  return stun_attr_get_first_by_type_str(buf->buf, (size_t)(buf->len), attr_type);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void stun_set_binding_request(stun_buffer* buf) {
+  stun_set_binding_request_str(buf->buf, (size_t*)(&(buf->len)));
+}
+
+int stun_set_binding_response(stun_buffer* buf, stun_tid* tid, 
+			      const ioa_addr *reflexive_addr, int error_code, const u08bits *reason) {
+  return stun_set_binding_response_str(buf->buf, (size_t*)(&(buf->len)), tid, 
+				       reflexive_addr, error_code, reason,
+				       0,0);
+}
+
+void stun_prepare_binding_request(stun_buffer* buf) {
+  stun_set_binding_request_str(buf->buf, (size_t*)(&(buf->len)));
+}
+
+int stun_is_binding_response(const stun_buffer* buf) {
+  return stun_is_binding_response_str(buf->buf, (size_t)(buf->len));
+}
+
+///////////////////////////////////////////////////////

+ 131 - 0
src/apps/common/stun_buffer.h

@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __TURN_STUN_BUF__
+#define __TURN_STUN_BUF__
+
+#include "ns_turn_msg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////
+
+typedef struct _stun_buffer {
+  u08bits	channel[STUN_CHANNEL_HEADER_LENGTH];
+  u08bits	buf[STUN_BUFFER_SIZE];
+  size_t	len;
+  u16bits	offset;
+  u08bits	coffset;
+} stun_buffer;
+
+//////////////////////////////////////////////////////////////
+
+int stun_init_buffer(stun_buffer *buf);
+int stun_get_size(const stun_buffer *buf);
+
+//////////////////////////////////////////////////////////////
+
+void stun_tid_generate_in_message(stun_buffer* buf, stun_tid* id);
+void stun_tid_from_message(const stun_buffer *buf, stun_tid* id);
+
+///////////////////////////////////////////////////////////////
+
+int stun_is_command_message(const stun_buffer* buf);
+int stun_is_request(const stun_buffer* buf);
+int stun_is_response(const stun_buffer* buf);
+int stun_is_success_response(const stun_buffer* buf);
+int stun_is_error_response(const stun_buffer* buf, int *err_code, u08bits *err_msg, size_t err_msg_size);
+int stun_is_indication(const stun_buffer* buf);
+u16bits stun_get_method(const stun_buffer* buf);
+u16bits stun_get_msg_type(const stun_buffer* buf);
+
+///////////////////////////////////////////////////////////////
+
+void stun_init_request(u16bits method, stun_buffer* buf);
+void stun_init_indication(u16bits method, stun_buffer* buf);
+void stun_init_success_response(u16bits method, stun_buffer* buf, stun_tid* id);
+void stun_init_error_response(u16bits method, stun_buffer* buf, u16bits error_code, const u08bits *reason, stun_tid* id);
+
+///////////////////////////////////////////////////////////////
+
+int stun_attr_add(stun_buffer* buf, u16bits attr, const s08bits* avalue, int alen);
+int stun_attr_add_channel_number(stun_buffer* buf, u16bits chnumber);
+int stun_attr_add_addr(stun_buffer *buf,u16bits attr_type, const ioa_addr* ca);
+
+stun_attr_ref stun_attr_get_first(const stun_buffer* buf);
+stun_attr_ref stun_attr_get_first_by_type(const stun_buffer* buf, u16bits attr_type);
+stun_attr_ref stun_attr_get_next(const stun_buffer* buf, stun_attr_ref prev);
+int stun_attr_get_addr(const stun_buffer *buf, stun_attr_ref attr, ioa_addr* ca, const ioa_addr *default_addr);
+int stun_attr_add_even_port(stun_buffer* buf, uint8_t value);
+
+int stun_attr_get_first_addr(const stun_buffer *buf, u16bits attr_type, ioa_addr* ca, const ioa_addr *default_addr);
+u16bits stun_attr_get_first_channel_number(const stun_buffer *buf);
+
+///////////////////////////////////////////////////////////////
+
+int stun_get_command_message_len(const stun_buffer* buf);
+
+///////////////////////////////////////////////////////////////
+
+int stun_init_channel_message(u16bits chnumber, stun_buffer* buf, int length, int do_padding);
+int stun_is_channel_message(stun_buffer* buf, u16bits* chnumber, int is_padding_madatory);
+
+///////////////////////////////////////////////////////////////
+
+int stun_set_allocate_request(stun_buffer* buf, u32bits lifetime, int address_family, u08bits transport, int mobile);
+int stun_set_allocate_response(stun_buffer* buf, stun_tid* tid, 
+			       const ioa_addr *relayed_addr, const ioa_addr *reflexive_addr,
+			       u32bits lifetime,
+			       int error_code, const u08bits *reason,
+			       u64bits reservation_token, char *mobile_id);
+
+///////////////////////////////////////////////////////////////
+
+void stun_set_binding_request(stun_buffer* buf);
+int stun_set_binding_response(stun_buffer* buf, stun_tid* tid, 
+			      const ioa_addr *reflexive_addr, int error_code, const u08bits *reason);
+
+void stun_prepare_binding_request(stun_buffer* buf);
+int stun_is_binding_response(const stun_buffer* buf);
+
+///////////////////////////////////////////////////////////////
+
+u16bits stun_set_channel_bind_request(stun_buffer* buf, const ioa_addr* peer_addr, u16bits channel_number);
+void stun_set_channel_bind_response(stun_buffer* buf, stun_tid* tid, int error_code, const u08bits *reason);
+
+///////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__TURN_STUN_BUF__

+ 102 - 0
src/apps/peer/mainudpserver.c

@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "ns_turn_utils.h"
+#include "udpserver.h"
+#include "apputils.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+//////////////// local definitions /////////////////
+
+static char Usage[] =
+  "Usage: server [options]\n"
+  "Options:\n"
+  "        -p      Listening UDP port (Default: 3480)\n"
+  "        -d      Listening interface device (optional)\n"
+  "        -L      Listening address\n"
+  "        -v      verbose\n";
+
+
+//////////////////////////////////////////////////
+
+int main(int argc, char **argv)
+{
+	int port = PEER_DEFAULT_PORT;
+	char **local_addr_list=NULL;
+	size_t las = 0;
+	int verbose = TURN_VERBOSE_NONE;
+	int c;
+	char ifname[1025] = "\0";
+
+	IS_TURN_SERVER = 1;
+
+	set_logfile("stdout");
+	set_system_parameters(0);
+
+	while ((c = getopt(argc, argv, "d:p:L:v")) != -1)
+		switch (c){
+		case 'd':
+			STRCPY(ifname, optarg);
+			break;
+		case 'p':
+			port = atoi(optarg);
+			break;
+		case 'L':
+		  local_addr_list = (char**)realloc(local_addr_list,++las*sizeof(char*));
+		  local_addr_list[las-1]=strdup(optarg);
+		  break;
+		case 'v':
+			verbose = TURN_VERBOSE_NORMAL;
+			break;
+		default:
+			fprintf(stderr, "%s\n", Usage);
+			exit(1);
+		}
+
+	if(las<1) {
+	  local_addr_list = (char**)realloc(local_addr_list,++las*sizeof(char*));
+	  local_addr_list[las-1]=strdup("0.0.0.0");
+	  local_addr_list = (char**)realloc(local_addr_list,++las*sizeof(char*));
+	  local_addr_list[las-1]=strdup("::");
+	}
+
+
+	server_type* server = start_udp_server(verbose, ifname, local_addr_list, las, port);
+	run_udp_server(server);
+	clean_udp_server(server);
+
+	return 0;
+}
+

+ 172 - 0
src/apps/peer/udpserver.c

@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "apputils.h"
+#include "udpserver.h"
+#include "stun_buffer.h"
+
+/////////////// io handlers ///////////////////
+
+static void udp_server_input_handler(evutil_socket_t fd, short what, void* arg) {
+
+  if(!(what&EV_READ)) return;
+
+  ioa_addr *addr = (ioa_addr*)arg;
+
+  int len = 0;
+  int slen = get_ioa_addr_len(addr);
+  stun_buffer buffer;
+  ioa_addr remote_addr;
+
+  do {
+    len = recvfrom(fd, buffer.buf, sizeof(buffer.buf)-1, 0, (struct sockaddr*) &remote_addr, (socklen_t*) &slen);
+  } while(len<0 && (errno==EINTR));
+  
+  buffer.len=len;
+
+  if(len>=0) {
+    do {
+      len = sendto(fd, buffer.buf, buffer.len, 0, (const struct sockaddr*) &remote_addr, (socklen_t) slen);
+    } while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN)));
+  }
+}
+
+///////////////////// operations //////////////////////////
+
+static int udp_create_server_socket(server_type* server, 
+				    const char* ifname, const char *local_address, int port) {
+
+  FUNCSTART;
+
+  if(!server) return -1;
+
+  evutil_socket_t udp_fd = -1;
+  ioa_addr *server_addr = (ioa_addr*)turn_malloc(sizeof(ioa_addr));
+
+  STRCPY(server->ifname,ifname);
+
+  if(make_ioa_addr((const u08bits*)local_address, port, server_addr)<0) return -1;
+  
+  udp_fd = socket(server_addr->ss.sa_family, SOCK_DGRAM, 0);
+  if (udp_fd < 0) {
+    perror("socket");
+    return -1;
+  }
+
+  if(sock_bind_to_device(udp_fd, (unsigned char*)server->ifname)<0) {
+    TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Cannot bind udp server socket to device %s\n",server->ifname);
+  }
+
+  set_sock_buf_size(udp_fd,UR_SERVER_SOCK_BUF_SIZE);
+  
+  if(addr_bind(udp_fd,server_addr,1)<0) return -1;
+  
+  socket_set_nonblocking(udp_fd);
+
+  struct event *udp_ev = event_new(server->event_base,udp_fd,EV_READ|EV_PERSIST,
+			     udp_server_input_handler,server_addr);
+  
+  event_add(udp_ev,NULL);
+  
+  FUNCEND;
+  
+  return 0;
+}
+
+static server_type* init_server(int verbose, const char* ifname, char **local_addresses, size_t las, int port) {
+
+  server_type* server=(server_type*)turn_malloc(sizeof(server_type));
+
+  if(!server) return server;
+
+  ns_bzero(server,sizeof(server_type));
+
+  server->verbose=verbose;
+
+  server->event_base = turn_event_base_new();
+
+  while(las) {
+    udp_create_server_socket(server, ifname, local_addresses[--las], port);
+    udp_create_server_socket(server, ifname, local_addresses[las], port+1);
+  }
+
+  return server;
+}
+
+static int clean_server(server_type* server) {
+  if(server) {
+    if(server->event_base) event_base_free(server->event_base);
+    turn_free(server,sizeof(server_type));
+  }
+  return 0;
+}
+
+///////////////////////////////////////////////////////////
+
+static void run_events(server_type* server) {
+
+  if(!server) return;
+
+  struct timeval timeout;
+
+  timeout.tv_sec=0;
+  timeout.tv_usec=100000;
+
+  event_base_loopexit(server->event_base, &timeout);
+  event_base_dispatch(server->event_base);
+}
+
+/////////////////////////////////////////////////////////////
+
+
+server_type* start_udp_server(int verbose, const char* ifname, char **local_addresses, size_t las, int port) {
+  return init_server(verbose, ifname, local_addresses, las, port);
+}
+
+void run_udp_server(server_type* server) {
+  
+  if(server) {
+    
+    unsigned int cycle=0;
+    
+    while (1) {
+      
+      cycle++;
+      
+      run_events(server);
+    }
+  }  
+}
+
+void clean_udp_server(server_type* server) {
+  if(server) clean_server(server);
+}
+
+//////////////////////////////////////////////////////////////////

+ 76 - 0
src/apps/peer/udpserver.h

@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __UDP_SERVER__
+#define __UDP_SERVER__
+
+//////////////////////////////
+
+#include "ns_turn_utils.h"
+
+#include <event2/event.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////////////
+
+struct server_info;
+typedef struct server_info server_type;
+
+///////////////////////////////////////////////////
+
+#define FUNCSTART if(server && server->verbose) turn_log_func_default(TURN_LOG_LEVEL_INFO,"%s:%d:start\n",__FUNCTION__,__LINE__)
+#define FUNCEND if(server && server->verbose) turn_log_func_default(TURN_LOG_LEVEL_INFO,"%s:%d:end\n",__FUNCTION__,__LINE__)
+
+///////////////////////////////////////////////////////
+
+struct server_info {
+  char ifname[1025];
+  struct event_base* event_base;
+  int verbose;
+};
+
+//////////////////////////////
+
+server_type* start_udp_server(int verbose, const char* ifname, char **local_addresses, size_t las, int port);
+
+void run_udp_server(server_type* server);
+
+void clean_udp_server(server_type* server);
+
+///////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__UDP_SERVER__

+ 954 - 0
src/apps/relay/dtls_listener.c

@@ -0,0 +1,954 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "apputils.h"
+#include "mainrelay.h"
+
+#include "dtls_listener.h"
+#include "ns_ioalib_impl.h"
+
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include <pthread.h>
+
+/* #define REQUEST_CLIENT_CERT */
+
+///////////////////////////////////////////////////
+
+#define FUNCSTART if(server && eve(server->verbose)) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s:%d:start\n",__FUNCTION__,__LINE__)
+#define FUNCEND if(server && eve(server->verbose)) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s:%d:end\n",__FUNCTION__,__LINE__)
+
+#define COOKIE_SECRET_LENGTH (32)
+
+#define MAX_SINGLE_UDP_BATCH (16)
+
+struct dtls_listener_relay_server_info {
+  char ifname[1025];
+  ioa_addr addr;
+  ioa_engine_handle e;
+  turn_turnserver *ts;
+  int verbose;
+  SSL_CTX *dtls_ctx;
+  struct event *udp_listen_ev;
+  ioa_socket_handle udp_listen_s;
+  ur_addr_map *children_ss; /* map of socket children on remote addr */
+  struct message_to_relay sm;
+  int slen0;
+  ioa_engine_new_connection_event_handler connect_cb;
+};
+
+///////////// forward declarations ////////
+
+static int create_server_socket(dtls_listener_relay_server_type* server, int report_creation);
+static int clean_server(dtls_listener_relay_server_type* server);
+static int reopen_server_socket(dtls_listener_relay_server_type* server, evutil_socket_t fd);
+
+///////////// dtls message types //////////
+
+int is_dtls_handshake_message(const unsigned char* buf, int len);
+int is_dtls_data_message(const unsigned char* buf, int len);
+int is_dtls_alert_message(const unsigned char* buf, int len);
+int is_dtls_cipher_change_message(const unsigned char* buf, int len);
+
+int is_dtls_message(const unsigned char* buf, int len);
+
+int is_dtls_handshake_message(const unsigned char* buf, int len) {
+  return (buf && len>3 && buf[0]==0x16 && buf[1]==0xfe && buf[2]==0xff);
+}
+
+int is_dtls_data_message(const unsigned char* buf, int len) {
+  return (buf && len>3 && buf[0]==0x17 && buf[1]==0xfe && buf[2]==0xff);
+}
+
+int is_dtls_alert_message(const unsigned char* buf, int len) {
+  return (buf && len>3 && buf[0]==0x15 && buf[1]==0xfe && buf[2]==0xff);
+}
+
+int is_dtls_cipher_change_message(const unsigned char* buf, int len) {
+  return (buf && len>3 && buf[0]==0x14 && buf[1]==0xfe && buf[2]==0xff);
+}
+
+int is_dtls_message(const unsigned char* buf, int len) {
+  if(buf && (len>3) && (buf[1])==0xfe && (buf[2]==0xff)) {
+	  switch (buf[0]) {
+	  case 0x14:
+	  case 0x15:
+	  case 0x16:
+	  case 0x17:
+		  return 1;
+	  default:
+		  ;
+	  }
+  }
+  return 0;
+}
+
+///////////// utils /////////////////////
+
+#if !defined(TURN_NO_DTLS)
+
+static void calculate_cookie(SSL* ssl, unsigned char *cookie_secret, unsigned int cookie_length) {
+  long rv=(long)ssl;
+  long inum=(cookie_length-(((long)cookie_secret)%sizeof(long)))/sizeof(long);
+  long i=0;
+  long *ip=(long*)cookie_secret;
+  for(i=0;i<inum;++i,++ip) *ip=rv;
+}
+
+static int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
+{
+  unsigned char *buffer, result[EVP_MAX_MD_SIZE];
+  unsigned int length = 0, resultlength;
+  ioa_addr peer;
+
+  unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
+  calculate_cookie(ssl, cookie_secret, sizeof(cookie_secret));
+  
+  /* Read peer information */
+  (void) BIO_dgram_get_peer(SSL_get_wbio(ssl), &peer);
+  
+  /* Create buffer with peer's address and port */
+  length = 0;
+  switch (peer.ss.sa_family) {
+  case AF_INET:
+    length += sizeof(struct in_addr);
+    break;
+  case AF_INET6:
+    length += sizeof(struct in6_addr);
+    break;
+  default:
+    OPENSSL_assert(0);
+    break;
+  }
+  length += sizeof(in_port_t);
+  buffer = (unsigned char*) OPENSSL_malloc(length);
+  
+  if (buffer == NULL) {
+    TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"out of memory\n");
+    return 0;
+  }
+  
+  switch (peer.ss.sa_family) {
+  case AF_INET:
+    memcpy(buffer,
+	   &peer.s4.sin_port,
+	   sizeof(in_port_t));
+    memcpy(buffer + sizeof(peer.s4.sin_port),
+	   &peer.s4.sin_addr,
+	   sizeof(struct in_addr));
+    break;
+  case AF_INET6:
+    memcpy(buffer,
+	   &peer.s6.sin6_port,
+	   sizeof(in_port_t));
+    memcpy(buffer + sizeof(in_port_t),
+	   &peer.s6.sin6_addr,
+	   sizeof(struct in6_addr));
+    break;
+  default:
+    OPENSSL_assert(0);
+    break;
+  }
+  
+  /* Calculate HMAC of buffer using the secret */
+  HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH,
+       (const unsigned char*) buffer, length, result, &resultlength);
+  OPENSSL_free(buffer);
+  
+  memcpy(cookie, result, resultlength);
+  *cookie_len = resultlength;
+  
+  return 1;
+}
+
+static int verify_cookie(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)
+{
+  unsigned int resultlength=0;
+  unsigned char result[COOKIE_SECRET_LENGTH];
+
+  generate_cookie(ssl, result, &resultlength);
+  
+  if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0) {
+    //TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s: cookies are OK, length=%u\n",__FUNCTION__,cookie_len);
+    return 1;
+  }
+  
+  return 0;
+}
+
+/////////////// io handlers ///////////////////
+
+static ioa_socket_handle dtls_accept_client_connection(
+				dtls_listener_relay_server_type* server,
+				ioa_socket_handle sock,
+				SSL *ssl,
+				ioa_addr *remote_addr, ioa_addr *local_addr,
+				ioa_network_buffer_handle nbh)
+{
+	FUNCSTART;
+
+	if (!ssl)
+		return NULL;
+
+	int rc = ssl_read(sock->fd, ssl, nbh, server->verbose);
+
+	if (rc < 0)
+		return NULL;
+
+	addr_debug_print(server->verbose, remote_addr, "Accepted connection from");
+
+	ioa_socket_handle ioas = create_ioa_socket_from_ssl(server->e, sock, ssl, DTLS_SOCKET, CLIENT_SOCKET, remote_addr, local_addr);
+	if(ioas) {
+
+		ioas->listener_server = server;
+
+		addr_cpy(&(server->sm.m.sm.nd.src_addr),remote_addr);
+		server->sm.m.sm.nd.recv_ttl = TTL_IGNORE;
+		server->sm.m.sm.nd.recv_tos = TOS_IGNORE;
+		server->sm.m.sm.s = ioas;
+	} else {
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot create ioa_socket from SSL\n");
+	}
+
+	FUNCEND	;
+
+	return ioas;
+}
+
+static ioa_socket_handle dtls_server_input_handler(dtls_listener_relay_server_type* server,
+				ioa_socket_handle s,
+				ioa_network_buffer_handle nbh)
+{
+	FUNCSTART;
+
+	if (!server || !nbh) {
+		return NULL;
+	}
+
+	SSL* connecting_ssl = NULL;
+
+	BIO *wbio = NULL;
+	struct timeval timeout;
+
+	/* Create BIO */
+	wbio = BIO_new_dgram(s->fd, BIO_NOCLOSE);
+	(void)BIO_dgram_set_peer(wbio, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr));
+
+	/* Set and activate timeouts */
+	timeout.tv_sec = DTLS_MAX_RECV_TIMEOUT;
+	timeout.tv_usec = 0;
+	BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
+
+	connecting_ssl = SSL_new(server->dtls_ctx);
+
+	SSL_set_accept_state(connecting_ssl);
+
+	SSL_set_bio(connecting_ssl, NULL, wbio);
+	SSL_set_options(connecting_ssl, SSL_OP_COOKIE_EXCHANGE);
+
+	SSL_set_max_cert_list(connecting_ssl, 655350);
+
+	ioa_socket_handle rc = dtls_accept_client_connection(server, s, connecting_ssl,
+					&(server->sm.m.sm.nd.src_addr),
+					&(server->addr),
+					nbh);
+
+	if (!rc) {
+		if (!(SSL_get_shutdown(connecting_ssl) & SSL_SENT_SHUTDOWN)) {
+			SSL_set_shutdown(connecting_ssl, SSL_RECEIVED_SHUTDOWN);
+			SSL_shutdown(connecting_ssl);
+		}
+		SSL_free(connecting_ssl);
+	}
+
+	return rc;
+}
+
+#endif
+
+static int handle_udp_packet(dtls_listener_relay_server_type *server,
+				struct message_to_relay *sm,
+				ioa_engine_handle ioa_eng, turn_turnserver *ts)
+{
+	int verbose = ioa_eng->verbose;
+	ioa_socket_handle s = sm->m.sm.s;
+
+	ur_addr_map_value_type mvt = 0;
+	if(!(server->children_ss)) {
+		server->children_ss = (ur_addr_map*)allocate_super_memory_engine(server->e, sizeof(ur_addr_map));
+		ur_addr_map_init(server->children_ss);
+	}
+	ur_addr_map *amap = server->children_ss;
+
+	ioa_socket_handle chs = NULL;
+	if ((ur_addr_map_get(amap, &(sm->m.sm.nd.src_addr), &mvt) > 0) && mvt) {
+		chs = (ioa_socket_handle) mvt;
+	}
+
+	if (chs && !ioa_socket_tobeclosed(chs)
+			&& (chs->sockets_container == amap)
+			&& (chs->magic == SOCKET_MAGIC)) {
+		s = chs;
+		sm->m.sm.s = s;
+		if(s->ssl) {
+			int sslret = ssl_read(s->fd, s->ssl, sm->m.sm.nd.nbh, verbose);
+			if(sslret < 0) {
+				ioa_network_buffer_delete(ioa_eng, sm->m.sm.nd.nbh);
+				sm->m.sm.nd.nbh = NULL;
+				ts_ur_super_session *ss = (ts_ur_super_session *) s->session;
+				if (ss) {
+					turn_turnserver *server = (turn_turnserver *) ss->server;
+					if (server) {
+						shutdown_client_connection(server, ss, 0, "SSL read error");
+					}
+				} else {
+					close_ioa_socket(s);
+				}
+				ur_addr_map_del(amap, &(sm->m.sm.nd.src_addr), NULL);
+				sm->m.sm.s = NULL;
+				s = NULL;
+				chs = NULL;
+			} else if(ioa_network_buffer_get_size(sm->m.sm.nd.nbh)>0) {
+				;
+			} else {
+				ioa_network_buffer_delete(ioa_eng, sm->m.sm.nd.nbh);
+				sm->m.sm.nd.nbh = NULL;
+			}
+		}
+
+		if (s && s->read_cb && sm->m.sm.nd.nbh) {
+			s->e = ioa_eng;
+			s->read_cb(s, IOA_EV_READ, &(sm->m.sm.nd), s->read_ctx);
+			ioa_network_buffer_delete(ioa_eng, sm->m.sm.nd.nbh);
+			sm->m.sm.nd.nbh = NULL;
+
+			if (ioa_socket_tobeclosed(s)) {
+				ts_ur_super_session *ss = (ts_ur_super_session *) s->session;
+				if (ss) {
+					turn_turnserver *server = (turn_turnserver *) ss->server;
+					if (server) {
+						shutdown_client_connection(server, ss, 0, "UDP packet processing error");
+					}
+				}
+			}
+		}
+	} else {
+		if (chs && ioa_socket_tobeclosed(chs)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+					"%s: socket to be closed\n", __FUNCTION__);
+			{
+				u08bits saddr[129];
+				u08bits rsaddr[129];
+				long thrid = (long) pthread_self();
+				addr_to_string(get_local_addr_from_ioa_socket(chs),saddr);
+				addr_to_string(get_remote_addr_from_ioa_socket(chs),rsaddr);
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+					"%s: 111.111: thrid=0x%lx: Amap = 0x%lx, socket container=0x%lx, local addr %s, remote addr %s, s=0x%lx, done=%d, tbc=%d\n",
+					__FUNCTION__, thrid, (long) amap,
+					(long) (chs->sockets_container), (char*) saddr,
+					(char*) rsaddr, (long) s, (int) (chs->done),
+					(int) (chs->tobeclosed));
+			}
+		}
+
+		if (chs && (chs->magic != SOCKET_MAGIC)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+					"%s: wrong socket magic\n", __FUNCTION__);
+		}
+
+		if (chs && (chs->sockets_container != amap)) {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+					"%s: wrong socket container\n", __FUNCTION__);
+			{
+				u08bits saddr[129];
+				u08bits rsaddr[129];
+				long thrid = (long) pthread_self();
+				addr_to_string(get_local_addr_from_ioa_socket(chs),saddr);
+				addr_to_string(get_remote_addr_from_ioa_socket(chs),rsaddr);
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+					"%s: 111.222: thrid=0x%lx: Amap = 0x%lx, socket container=0x%lx, local addr %s, remote addr %s, s=0x%lx, done=%d, tbc=%d, st=%d, sat=%d\n",
+					__FUNCTION__, thrid, (long) amap,
+					(long) (chs->sockets_container), (char*) saddr,
+					(char*) rsaddr, (long) chs, (int) (chs->done),
+					(int) (chs->tobeclosed), (int) (chs->st),
+					(int) (chs->sat));
+			}
+		}
+
+		chs = NULL;
+
+#if !defined(TURN_NO_DTLS)
+		if (!turn_params.no_dtls &&
+			is_dtls_handshake_message(ioa_network_buffer_data(sm->m.sm.nd.nbh),
+			(int)ioa_network_buffer_get_size(sm->m.sm.nd.nbh))) {
+			chs = dtls_server_input_handler(server,s, sm->m.sm.nd.nbh);
+			ioa_network_buffer_delete(server->e, sm->m.sm.nd.nbh);
+			sm->m.sm.nd.nbh = NULL;
+		}
+#endif
+
+		if(!chs) {
+			chs = create_ioa_socket_from_fd(ioa_eng, s->fd, s,
+				UDP_SOCKET, CLIENT_SOCKET, &(sm->m.sm.nd.src_addr),
+				get_local_addr_from_ioa_socket(s));
+		}
+
+		s = chs;
+		sm->m.sm.s = s;
+
+		if (s) {
+			if(verbose) {
+				u08bits saddr[129];
+				u08bits rsaddr[129];
+				addr_to_string(get_local_addr_from_ioa_socket(s),saddr);
+				addr_to_string(get_remote_addr_from_ioa_socket(s),rsaddr);
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+					"%s: New UDP endpoint: local addr %s, remote addr %s\n",
+					__FUNCTION__, (char*) saddr,(char*) rsaddr);
+			}
+			s->e = ioa_eng;
+			s->listener_server = server;
+			add_socket_to_map(s, amap);
+			open_client_connection_session(ts, &(sm->m.sm));
+		}
+	}
+
+	return 0;
+}
+
+static int create_new_connected_udp_socket(
+		dtls_listener_relay_server_type* server, ioa_socket_handle s)
+{
+
+	evutil_socket_t udp_fd = socket(s->local_addr.ss.sa_family, SOCK_DGRAM, 0);
+	if (udp_fd < 0) {
+		perror("socket");
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot allocate new socket\n",
+				__FUNCTION__);
+		return -1;
+	}
+
+	if (sock_bind_to_device(udp_fd, (unsigned char*) (s->e->relay_ifname))
+			< 0) {
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+				"Cannot bind udp server socket to device %s\n",
+				(char*) (s->e->relay_ifname));
+	}
+
+	ioa_socket_handle ret = (ioa_socket*) turn_malloc(sizeof(ioa_socket));
+	if (!ret) {
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+				"%s: Cannot allocate new socket structure\n", __FUNCTION__);
+		close(udp_fd);
+		return -1;
+	}
+
+	ns_bzero(ret, sizeof(ioa_socket));
+
+	ret->magic = SOCKET_MAGIC;
+
+	ret->fd = udp_fd;
+
+	ret->family = s->family;
+	ret->st = s->st;
+	ret->sat = CLIENT_SOCKET;
+	ret->local_addr_known = 1;
+	addr_cpy(&(ret->local_addr), &(s->local_addr));
+
+	if (addr_bind(udp_fd,&(s->local_addr),1) < 0) {
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+				"Cannot bind new detached udp server socket to local addr\n");
+		IOA_CLOSE_SOCKET(ret);
+		return -1;
+	}
+	ret->bound = 1;
+
+	{
+		int connect_err = 0;
+		if (addr_connect(udp_fd, &(server->sm.m.sm.nd.src_addr), &connect_err) < 0) {
+			char sl[129];
+			char sr[129];
+			addr_to_string(&(ret->local_addr),(u08bits*)sl);
+			addr_to_string(&(server->sm.m.sm.nd.src_addr),(u08bits*)sr);
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+					"Cannot connect new detached udp client socket from local addr %s to remote addr %s\n",sl,sr);
+			IOA_CLOSE_SOCKET(ret);
+			return -1;
+		}
+	}
+	ret->connected = 1;
+	addr_cpy(&(ret->remote_addr), &(server->sm.m.sm.nd.src_addr));
+
+	set_socket_options(ret);
+
+	ret->current_ttl = s->current_ttl;
+	ret->default_ttl = s->default_ttl;
+
+	ret->current_tos = s->current_tos;
+	ret->default_tos = s->default_tos;
+
+#if !defined(TURN_NO_DTLS)
+	if (!turn_params.no_dtls
+			&& is_dtls_handshake_message(
+					ioa_network_buffer_data(server->sm.m.sm.nd.nbh),
+					(int) ioa_network_buffer_get_size(
+							server->sm.m.sm.nd.nbh))) {
+
+		SSL* connecting_ssl = NULL;
+
+		BIO *wbio = NULL;
+		struct timeval timeout;
+
+		/* Create BIO */
+		wbio = BIO_new_dgram(ret->fd, BIO_NOCLOSE);
+		(void) BIO_dgram_set_peer(wbio, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr));
+
+		BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &(server->sm.m.sm.nd.src_addr));
+
+		/* Set and activate timeouts */
+		timeout.tv_sec = DTLS_MAX_RECV_TIMEOUT;
+		timeout.tv_usec = 0;
+		BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
+
+		connecting_ssl = SSL_new(server->dtls_ctx);
+
+		SSL_set_accept_state(connecting_ssl);
+
+		SSL_set_bio(connecting_ssl, NULL, wbio);
+
+		SSL_set_options(connecting_ssl, SSL_OP_COOKIE_EXCHANGE);
+		SSL_set_max_cert_list(connecting_ssl, 655350);
+		int rc = ssl_read(ret->fd, connecting_ssl, server->sm.m.sm.nd.nbh,
+				server->verbose);
+
+		if (rc < 0) {
+			if (!(SSL_get_shutdown(connecting_ssl) & SSL_SENT_SHUTDOWN)) {
+				SSL_set_shutdown(connecting_ssl, SSL_RECEIVED_SHUTDOWN);
+				SSL_shutdown(connecting_ssl);
+			}
+			SSL_free(connecting_ssl);
+			IOA_CLOSE_SOCKET(ret);
+			return -1;
+		}
+
+		addr_debug_print(server->verbose, &(server->sm.m.sm.nd.src_addr),
+				"Accepted DTLS connection from");
+
+		ret->ssl = connecting_ssl;
+		ret->listener_server = server;
+
+		ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh);
+		server->sm.m.sm.nd.nbh = NULL;
+	}
+#endif
+
+	server->sm.m.sm.s = ret;
+	return server->connect_cb(server->e, &(server->sm));
+}
+
+static void udp_server_input_handler(evutil_socket_t fd, short what, void* arg)
+{
+	int cycle = 0;
+
+	ioa_socket_handle s = (ioa_socket_handle)arg;
+
+	dtls_listener_relay_server_type* server = (dtls_listener_relay_server_type*)s->listener_server;
+
+	FUNCSTART;
+
+	if (!(what & EV_READ)) {
+		return;
+	}
+
+	//printf_server_socket(server, fd);
+
+	ioa_network_buffer_handle *elem = NULL;
+
+	start_udp_cycle:
+
+	elem = (ioa_network_buffer_handle *)ioa_network_buffer_allocate(server->e);
+
+	server->sm.m.sm.nd.nbh = elem;
+	server->sm.m.sm.nd.recv_ttl = TTL_IGNORE;
+	server->sm.m.sm.nd.recv_tos = TOS_IGNORE;
+
+	addr_set_any(&(server->sm.m.sm.nd.src_addr));
+
+	int slen = server->slen0;
+	ssize_t bsize = 0;
+
+	int flags = 0;
+
+	do {
+		bsize = recvfrom(fd, ioa_network_buffer_data(elem), ioa_network_buffer_get_capacity_udp(), flags, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr), (socklen_t*) &slen);
+	} while (bsize < 0 && (errno == EINTR));
+
+	int conn_reset = is_connreset();
+	int to_block = would_block();
+
+	if (bsize < 0) {
+
+		if(to_block) {
+			ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh);
+			server->sm.m.sm.nd.nbh = NULL;
+			FUNCEND;
+			return;
+		}
+
+	#if defined(MSG_ERRQUEUE)
+
+		//Linux
+		int eflags = MSG_ERRQUEUE | MSG_DONTWAIT;
+		static s08bits buffer[65535];
+		u32bits errcode = 0;
+		ioa_addr orig_addr;
+		int ttl = 0;
+		int tos = 0;
+		udp_recvfrom(fd, &orig_addr, &(server->addr), buffer,
+					(int) sizeof(buffer), &ttl, &tos, server->e->cmsg, eflags,
+					&errcode);
+		//try again...
+		do {
+			bsize = recvfrom(fd, ioa_network_buffer_data(elem), ioa_network_buffer_get_capacity_udp(), flags, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr), (socklen_t*) &slen);
+		} while (bsize < 0 && (errno == EINTR));
+
+		conn_reset = is_connreset();
+		to_block = would_block();
+
+	#endif
+
+		if(conn_reset) {
+			ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh);
+			server->sm.m.sm.nd.nbh = NULL;
+			reopen_server_socket(server,fd);
+			FUNCEND;
+			return;
+		}
+	}
+
+	if(bsize<0) {
+		if(!to_block && !conn_reset) {
+			int ern=errno;
+			perror(__FUNCTION__);
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: recvfrom error %d\n",__FUNCTION__,ern);
+		}
+		ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh);
+		server->sm.m.sm.nd.nbh = NULL;
+		FUNCEND;
+		return;
+	}
+
+	if (bsize > 0) {
+
+		int rc = 0;
+		ioa_network_buffer_set_size(elem, (size_t)bsize);
+
+		if(server->connect_cb) {
+
+			rc = create_new_connected_udp_socket(server, s);
+			if(rc<0) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot handle UDP packet, size %d\n",(int)bsize);
+			}
+
+		} else {
+			server->sm.m.sm.s = s;
+			rc = handle_udp_packet(server, &(server->sm), server->e, server->ts);
+		}
+
+		if(rc < 0) {
+			if(eve(server->e->verbose)) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot handle UDP event\n");
+			}
+		}
+	}
+
+	ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh);
+	server->sm.m.sm.nd.nbh = NULL;
+
+	if((bsize>0) && (cycle++<MAX_SINGLE_UDP_BATCH))
+		goto start_udp_cycle;
+
+	FUNCEND;
+}
+
+///////////////////// operations //////////////////////////
+
+static int create_server_socket(dtls_listener_relay_server_type* server, int report_creation) {
+
+  FUNCSTART;
+
+  if(!server) return -1;
+
+  clean_server(server);
+
+  {
+	  ioa_socket_raw udp_listen_fd = -1;
+
+	  udp_listen_fd = socket(server->addr.ss.sa_family, SOCK_DGRAM, 0);
+	  if (udp_listen_fd < 0) {
+		  perror("socket");
+		  return -1;
+	  }
+
+	  server->udp_listen_s = create_ioa_socket_from_fd(server->e, udp_listen_fd, NULL, UDP_SOCKET, LISTENER_SOCKET, NULL, &(server->addr));
+
+	  server->udp_listen_s->listener_server = server;
+
+	  set_sock_buf_size(udp_listen_fd,UR_SERVER_SOCK_BUF_SIZE);
+
+	  if(sock_bind_to_device(udp_listen_fd, (unsigned char*)server->ifname)<0) {
+		  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Cannot bind listener socket to device %s\n",server->ifname);
+	  }
+
+	  {
+		  const int max_binding_time = 60;
+		  int addr_bind_cycle = 0;
+		  retry_addr_bind:
+
+		  if(addr_bind(udp_listen_fd,&server->addr,1)<0) {
+			  perror("Cannot bind local socket to addr");
+			  char saddr[129];
+			  addr_to_string(&server->addr,(u08bits*)saddr);
+			  TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING,"Cannot bind UDP/DTLS listener socket to addr %s\n",saddr);
+			  if(addr_bind_cycle++<max_binding_time) {
+				  TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Trying to bind UDP/DTLS listener socket to addr %s, again...\n",saddr);
+				  sleep(1);
+				  goto retry_addr_bind;
+			  }
+			  TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"Fatal final failure: cannot bind UDP/DTLS listener socket to addr %s\n",saddr);
+			  exit(-1);
+		  }
+	  }
+
+	  server->udp_listen_ev = event_new(server->e->event_base,udp_listen_fd,
+				    EV_READ|EV_PERSIST,udp_server_input_handler,
+				    server->udp_listen_s);
+
+	  event_add(server->udp_listen_ev,NULL);
+  }
+
+  if(report_creation) {
+	  if(!turn_params.no_udp && !turn_params.no_dtls)
+		  addr_debug_print(server->verbose, &server->addr,"UDP/DTLS listener opened on");
+	  else if(!turn_params.no_dtls)
+		  addr_debug_print(server->verbose, &server->addr,"DTLS listener opened on");
+	  else if(!turn_params.no_udp)
+		  addr_debug_print(server->verbose, &server->addr,"UDP listener opened on");
+  }
+
+  FUNCEND;
+  
+  return 0;
+}
+
+static int reopen_server_socket(dtls_listener_relay_server_type* server, evutil_socket_t fd)
+{
+	UNUSED_ARG(fd);
+
+	if(!server)
+		return 0;
+
+	FUNCSTART;
+
+	{
+		EVENT_DEL(server->udp_listen_ev);
+
+		if(server->udp_listen_s->fd>=0) {
+			socket_closesocket(server->udp_listen_s->fd);
+			server->udp_listen_s->fd = -1;
+		}
+
+		if (!(server->udp_listen_s)) {
+			return create_server_socket(server,1);
+		}
+
+		ioa_socket_raw udp_listen_fd = socket(server->addr.ss.sa_family, SOCK_DGRAM, 0);
+		if (udp_listen_fd < 0) {
+			perror("socket");
+			FUNCEND;
+			return -1;
+		}
+
+		server->udp_listen_s->fd = udp_listen_fd;
+
+		/* some UDP sessions may fail due to the race condition here */
+
+		set_socket_options(server->udp_listen_s);
+
+		set_sock_buf_size(udp_listen_fd, UR_SERVER_SOCK_BUF_SIZE);
+
+		if (sock_bind_to_device(udp_listen_fd, (unsigned char*) server->ifname) < 0) {
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
+				"Cannot bind listener socket to device %s\n",
+				server->ifname);
+		}
+
+		if(addr_bind(udp_listen_fd,&server->addr,1)<0) {
+			perror("Cannot bind local socket to addr");
+			char saddr[129];
+			addr_to_string(&server->addr,(u08bits*)saddr);
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"Cannot bind listener socket to addr %s\n",saddr);
+			return -1;
+		}
+
+		server->udp_listen_ev = event_new(server->e->event_base, udp_listen_fd,
+				EV_READ | EV_PERSIST, udp_server_input_handler,
+				server->udp_listen_s);
+
+		event_add(server->udp_listen_ev, NULL );
+	}
+
+	if (!turn_params.no_udp && !turn_params.no_dtls)
+		addr_debug_print(server->verbose, &server->addr,
+					"UDP/DTLS listener opened on ");
+	else if (!turn_params.no_dtls)
+		addr_debug_print(server->verbose, &server->addr,
+					"DTLS listener opened on ");
+	else if (!turn_params.no_udp)
+		addr_debug_print(server->verbose, &server->addr,
+				"UDP listener opened on ");
+
+	FUNCEND;
+
+	return 0;
+}
+
+#if defined(REQUEST_CLIENT_CERT)
+
+static int dtls_verify_callback (int ok, X509_STORE_CTX *ctx) {
+  /* This function should ask the user
+   * if he trusts the received certificate.
+   * Here we always trust.
+   */
+  if(ok && ctx) return 1;
+  return -1;
+}
+
+#endif
+
+static int init_server(dtls_listener_relay_server_type* server,
+		       const char* ifname,
+		       const char *local_address, 
+		       int port, 
+		       int verbose,
+		       ioa_engine_handle e,
+		       turn_turnserver *ts,
+		       int report_creation,
+		       ioa_engine_new_connection_event_handler send_socket) {
+
+  if(!server) return -1;
+
+  server->dtls_ctx = e->dtls_ctx;
+  server->ts = ts;
+  server->connect_cb = send_socket;
+
+  if(ifname) STRCPY(server->ifname,ifname);
+
+  if(make_ioa_addr((const u08bits*)local_address, port, &server->addr)<0) {
+	  TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"Cannot create a UDP/DTLS listener for address: %s\n",local_address);
+	  return -1;
+  }
+
+  server->slen0 = get_ioa_addr_len(&(server->addr));
+
+  server->verbose=verbose;
+  
+  server->e = e;
+  
+  if(server->dtls_ctx) {
+
+#if defined(REQUEST_CLIENT_CERT)
+	  /* If client has to authenticate, then  */
+	  SSL_CTX_set_verify(server->dtls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback);
+#endif
+  
+	  SSL_CTX_set_read_ahead(server->dtls_ctx, 1);
+
+#if !defined(TURN_NO_DTLS)
+	  SSL_CTX_set_cookie_generate_cb(server->dtls_ctx, generate_cookie);
+	  SSL_CTX_set_cookie_verify_cb(server->dtls_ctx, verify_cookie);
+#endif
+  }
+
+  return create_server_socket(server, report_creation);
+}
+
+static int clean_server(dtls_listener_relay_server_type* server) {
+  if(server) {
+	  EVENT_DEL(server->udp_listen_ev);
+	  close_ioa_socket(server->udp_listen_s);
+	  server->udp_listen_s = NULL;
+  }
+  return 0;
+}
+
+///////////////////////////////////////////////////////////
+
+dtls_listener_relay_server_type* create_dtls_listener_server(const char* ifname,
+							     const char *local_address, 
+							     int port, 
+							     int verbose,
+							     ioa_engine_handle e,
+							     turn_turnserver *ts,
+							     int report_creation,
+							     ioa_engine_new_connection_event_handler send_socket) {
+  
+  dtls_listener_relay_server_type* server=(dtls_listener_relay_server_type*)
+		allocate_super_memory_engine(e,sizeof(dtls_listener_relay_server_type));
+
+  if(init_server(server,
+		 ifname, local_address, port,
+		 verbose,
+		 e, ts, report_creation, send_socket)<0) {
+    return NULL;
+  } else {
+    return server;
+  }
+}
+
+ioa_engine_handle get_engine(dtls_listener_relay_server_type* server)
+{
+	if(server)
+		return server->e;
+	return NULL;
+}
+
+//////////// UDP send ////////////////
+
+void udp_send_message(dtls_listener_relay_server_type *server, ioa_network_buffer_handle nbh, ioa_addr *dest)
+{
+	if(server && dest && nbh && (server->udp_listen_s))
+		udp_send(server->udp_listen_s, dest, (s08bits*)ioa_network_buffer_data(nbh), (int)ioa_network_buffer_get_size(nbh));
+}
+
+//////////////////////////////////////////////////////////////////

+ 72 - 0
src/apps/relay/dtls_listener.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011, 2012, 2013 Citrix Systems
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __DTLS_LISTENER__
+#define __DTLS_LISTENER__
+
+#include "ns_turn_utils.h"
+
+#include "ns_ioalib_impl.h"
+
+#include "ns_turn_server.h"
+
+#include <event2/event.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////
+
+struct dtls_listener_relay_server_info;
+typedef struct dtls_listener_relay_server_info dtls_listener_relay_server_type;
+
+///////////////////////////////////////////
+
+dtls_listener_relay_server_type* create_dtls_listener_server(const char* ifname,
+							     const char *local_address, 
+							     int port,
+							     int verbose,
+							     ioa_engine_handle e,
+							     turn_turnserver *ts,
+							     int report_creation,
+							     ioa_engine_new_connection_event_handler send_socket);
+
+void udp_send_message(dtls_listener_relay_server_type *server, ioa_network_buffer_handle nbh, ioa_addr *dest);
+
+ioa_engine_handle get_engine(dtls_listener_relay_server_type* server);
+
+///////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__DTLS_LISTENER__

+ 1545 - 0
src/apps/relay/libtelnet.c

@@ -0,0 +1,1545 @@
+/*
+ * libtelnet - TELNET protocol handling library
+ *
+ * Sean Middleditch
+ * [email protected]
+ *
+ * The author or authors of this code dedicate any and all copyright interest
+ * in this code to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and successors. We
+ * intend this dedication to be an overt act of relinquishment in perpetuity of
+ * all present and future rights to this code under copyright law.
+ */
+
+/**
+ * Minor fixes by Oleg Moskalenko
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+
+/* Win32 compatibility */
+#if defined(_WIN32)
+# define vsnprintf _vsnprintf
+# define __func__ __FUNCTION__
+# define ZLIB_WINAPI 1
+#endif
+
+#if defined(HAVE_ZLIB)
+# include <zlib.h>
+#endif
+
+#include "libtelnet.h"
+
+/* inlinable functions */
+#if defined(__GNUC__) || __STDC_VERSION__ >= 199901L
+# define INLINE __inline__
+#else
+# define INLINE
+#endif
+
+/* helper for Q-method option tracking */
+#define Q_US(q) ((q).state & 0x0F)
+#define Q_HIM(q) (((q).state & 0xF0) >> 4)
+#define Q_MAKE(us,him) ((us) | ((him) << 4))
+
+/* helper for the negotiation routines */
+#define NEGOTIATE_EVENT(telnet,cmd,opt) \
+	ev.type = (cmd); \
+	ev.neg.telopt = (opt); \
+	(telnet)->eh((telnet), &ev, (telnet)->ud);
+
+/* telnet state codes */
+enum telnet_state_t {
+	TELNET_STATE_DATA = 0,
+	TELNET_STATE_IAC,
+	TELNET_STATE_WILL,
+	TELNET_STATE_WONT,
+	TELNET_STATE_DO,
+	TELNET_STATE_DONT,
+	TELNET_STATE_SB,
+	TELNET_STATE_SB_DATA,
+	TELNET_STATE_SB_DATA_IAC
+};
+typedef enum telnet_state_t telnet_state_t;
+
+/* telnet state tracker */
+struct telnet_t {
+	/* user data */
+	void *ud;
+	/* telopt support table */
+	const telnet_telopt_t *telopts;
+	/* event handler */
+	telnet_event_handler_t eh;
+#if defined(HAVE_ZLIB)
+	/* zlib (mccp2) compression */
+	z_stream *z;
+#endif
+	/* RFC1143 option negotiation states */
+	struct telnet_rfc1143_t *q;
+	/* sub-request buffer */
+	char *buffer;
+	/* current size of the buffer */
+	size_t buffer_size;
+	/* current buffer write position (also length of buffer data) */
+	size_t buffer_pos;
+	/* current state */
+	enum telnet_state_t state;
+	/* option flags */
+	unsigned char flags;
+	/* current subnegotiation telopt */
+	unsigned char sb_telopt;
+	/* length of RFC1143 queue */
+	unsigned char q_size;
+};
+
+/* RFC1143 option negotiation state */
+typedef struct telnet_rfc1143_t {
+	unsigned char telopt;
+	unsigned char state;
+} telnet_rfc1143_t;
+
+/* RFC1143 state names */
+#define Q_NO 0
+#define Q_YES 1
+#define Q_WANTNO 2
+#define Q_WANTYES 3
+#define Q_WANTNO_OP 4
+#define Q_WANTYES_OP 5
+
+/* buffer sizes */
+static const size_t _buffer_sizes[] = { 0, 512, 2048, 8192, 16384, };
+static const size_t _buffer_sizes_count = sizeof(_buffer_sizes) /
+		sizeof(_buffer_sizes[0]);
+
+/* error generation function */
+static telnet_error_t _error(telnet_t *telnet, unsigned line,
+		const char* func, telnet_error_t err, int fatal, const char *fmt,
+		...) {
+	telnet_event_t ev;
+	char buffer[512];
+	va_list va;
+
+	/* format informational text */
+	va_start(va, fmt);
+	vsnprintf(buffer, sizeof(buffer), fmt, va);
+	va_end(va);
+
+	/* send error event to the user */
+	ev.type = fatal ? TELNET_EV_ERROR : TELNET_EV_WARNING;
+	ev.error.file = __FILE__;
+	ev.error.func = func;
+	ev.error.line = line;
+	ev.error.msg = buffer;
+	telnet->eh(telnet, &ev, telnet->ud);
+	
+	return err;
+}
+
+#if defined(HAVE_ZLIB)
+/* initialize the zlib box for a telnet box; if deflate is non-zero, it
+ * initializes zlib for delating (compression), otherwise for inflating
+ * (decompression).  returns TELNET_EOK on success, something else on
+ * failure.
+ */
+telnet_error_t _init_zlib(telnet_t *telnet, int deflate, int err_fatal) {
+	z_stream *z;
+	int rs;
+
+	/* if compression is already enabled, fail loudly */
+	if (telnet->z != 0)
+		return _error(telnet, __LINE__, __func__, TELNET_EBADVAL,
+				err_fatal, "cannot initialize compression twice");
+
+	/* allocate zstream box */
+	if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
+		return _error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal,
+				"malloc() failed: %s", strerror(errno));
+
+	/* initialize */
+	if (deflate) {
+		if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
+			free(z);
+			return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
+					err_fatal, "deflateInit() failed: %s", zError(rs));
+		}
+		telnet->flags |= TELNET_PFLAG_DEFLATE;
+	} else {
+		if ((rs = inflateInit(z)) != Z_OK) {
+			free(z);
+			return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
+					err_fatal, "inflateInit() failed: %s", zError(rs));
+		}
+		telnet->flags &= ~TELNET_PFLAG_DEFLATE;
+	}
+
+	telnet->z = z;
+
+	return TELNET_EOK;
+}
+#endif /* defined(HAVE_ZLIB) */
+
+/* push bytes out, compressing them first if need be */
+static void _send(telnet_t *telnet, const char *buffer,
+		size_t size) {
+	telnet_event_t ev;
+
+#if defined(HAVE_ZLIB)
+	/* if we have a deflate (compression) zlib box, use it */
+	if (telnet->z != 0 && telnet->flags & TELNET_PFLAG_DEFLATE) {
+		char deflate_buffer[1024];
+		int rs;
+
+		/* initialize z state */
+		telnet->z->next_in = (unsigned char *)buffer;
+		telnet->z->avail_in = size;
+		telnet->z->next_out = (unsigned char *)deflate_buffer;
+		telnet->z->avail_out = sizeof(deflate_buffer);
+
+		/* deflate until buffer exhausted and all output is produced */
+		while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
+			/* compress */
+			if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
+				_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
+						"deflate() failed: %s", zError(rs));
+				deflateEnd(telnet->z);
+				free(telnet->z);
+				telnet->z = 0;
+				break;
+			}
+
+			/* send event */
+			ev.type = TELNET_EV_SEND;
+			ev.data.buffer = deflate_buffer;
+			ev.data.size = sizeof(deflate_buffer) - telnet->z->avail_out;
+			telnet->eh(telnet, &ev, telnet->ud);
+
+			/* prepare output buffer for next run */
+			telnet->z->next_out = (unsigned char *)deflate_buffer;
+			telnet->z->avail_out = sizeof(deflate_buffer);
+		}
+
+		/* do not continue with remaining code */
+		return;
+	}
+#endif /* defined(HAVE_ZLIB) */
+
+	ev.type = TELNET_EV_SEND;
+	ev.data.buffer = buffer;
+	ev.data.size = size;
+	telnet->eh(telnet, &ev, telnet->ud);
+}
+
+/* to send bags of unsigned chars */
+#define _sendu(t, d, s) _send((t), (const char*)(d), (s))
+
+/* check if we support a particular telopt; if us is non-zero, we
+ * check if we (local) supports it, otherwise we check if he (remote)
+ * supports it.  return non-zero if supported, zero if not supported.
+ */
+static INLINE int _check_telopt(telnet_t *telnet, unsigned char telopt,
+		int us) {
+	int i;
+
+	/* if we have no telopts table, we obviously don't support it */
+	if (telnet->telopts == 0)
+		return 0;
+
+	/* loop unti found or end marker (us and him both 0) */
+	for (i = 0; telnet->telopts[i].telopt != -1; ++i) {
+		if (telnet->telopts[i].telopt == telopt) {
+			if (us && telnet->telopts[i].us == TELNET_WILL)
+				return 1;
+			else if (!us && telnet->telopts[i].him == TELNET_DO)
+				return 1;
+			else
+				return 0;
+		}
+	}
+
+	/* not found, so not supported */
+	return 0;
+}
+
+/* retrieve RFC1143 option state */
+static INLINE telnet_rfc1143_t _get_rfc1143(telnet_t *telnet,
+		unsigned char telopt) {
+	telnet_rfc1143_t empty;
+	int i;
+
+	/* search for entry */
+	for (i = 0; i != telnet->q_size; ++i) {
+		if (telnet->q[i].telopt == telopt) {
+			return telnet->q[i];
+		}
+	}
+
+	/* not found, return empty value */
+ 	empty.telopt = telopt;
+	empty.state = 0;
+	return empty;
+}
+
+/* save RFC1143 option state */
+static INLINE void _set_rfc1143(telnet_t *telnet, unsigned char telopt,
+		char us, char him) {
+	telnet_rfc1143_t *qtmp;
+	int i;
+
+	/* search for entry */
+	for (i = 0; i != telnet->q_size; ++i) {
+		if (telnet->q[i].telopt == telopt) {
+			telnet->q[i].state = Q_MAKE(us,him);
+			return;
+		}
+	}
+
+	/* we're going to need to track state for it, so grow the queue
+	 * by 4 (four) elements and put the telopt into it; bail on allocation
+	 * error.  we go by four because it seems like a reasonable guess as
+	 * to the number of enabled options for most simple code, and it
+	 * allows for an acceptable number of reallocations for complex code.
+	 */
+	if ((qtmp = (telnet_rfc1143_t *)realloc(telnet->q,
+			sizeof(telnet_rfc1143_t) * (telnet->q_size + 4))) == 0) {
+		_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+				"realloc() failed: %s", strerror(errno));
+		return;
+	}
+	memset(&qtmp[telnet->q_size], 0, sizeof(telnet_rfc1143_t) * 4);
+	telnet->q = qtmp;
+	telnet->q[telnet->q_size].telopt = telopt;
+	telnet->q[telnet->q_size].state = Q_MAKE(us, him);
+	telnet->q_size += 4;
+}
+
+/* send negotiation bytes */
+static INLINE void _send_negotiate(telnet_t *telnet, unsigned char cmd,
+		unsigned char telopt) {
+	unsigned char bytes[3];
+	bytes[0] = TELNET_IAC;
+	bytes[1] = cmd;
+	bytes[2] = telopt;
+	_sendu(telnet, bytes, 3);
+}
+
+/* negotiation handling magic for RFC1143 */
+static void _negotiate(telnet_t *telnet, unsigned char telopt) {
+	telnet_event_t ev;
+	telnet_rfc1143_t q;
+
+	/* in PROXY mode, just pass it thru and do nothing */
+	if (telnet->flags & TELNET_FLAG_PROXY) {
+		switch ((int)telnet->state) {
+		case TELNET_STATE_WILL:
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
+			break;
+		case TELNET_STATE_WONT:
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
+			break;
+		case TELNET_STATE_DO:
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
+			break;
+		case TELNET_STATE_DONT:
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
+			break;
+		}
+		return;
+	}
+
+	/* lookup the current state of the option */
+	q = _get_rfc1143(telnet, telopt);
+
+	/* start processing... */
+	switch ((int)telnet->state) {
+	/* request to enable option on remote end or confirm DO */
+	case TELNET_STATE_WILL:
+		switch (Q_HIM(q)) {
+		case Q_NO:
+			if (_check_telopt(telnet, telopt, 0)) {
+				_set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
+				_send_negotiate(telnet, TELNET_DO, telopt);
+				NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
+			} else
+				_send_negotiate(telnet, TELNET_DONT, telopt);
+			break;
+		case Q_WANTNO:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
+			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+					"DONT answered by WILL");
+			break;
+		case Q_WANTNO_OP:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
+			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+					"DONT answered by WILL");
+			break;
+		case Q_WANTYES:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
+			break;
+		case Q_WANTYES_OP:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
+			_send_negotiate(telnet, TELNET_DONT, telopt);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
+			break;
+		}
+		break;
+
+	/* request to disable option on remote end, confirm DONT, reject DO */
+	case TELNET_STATE_WONT:
+		switch (Q_HIM(q)) {
+		case Q_YES:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
+			_send_negotiate(telnet, TELNET_DONT, telopt);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
+			break;
+		case Q_WANTNO:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
+			break;
+		case Q_WANTNO_OP:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
+			break;
+		case Q_WANTYES:
+		case Q_WANTYES_OP:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
+			break;
+		}
+		break;
+
+	/* request to enable option on local end or confirm WILL */
+	case TELNET_STATE_DO:
+		switch (Q_US(q)) {
+		case Q_NO:
+			if (_check_telopt(telnet, telopt, 1)) {
+				_set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
+				_send_negotiate(telnet, TELNET_WILL, telopt);
+				NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
+			} else
+				_send_negotiate(telnet, TELNET_WONT, telopt);
+			break;
+		case Q_WANTNO:
+			_set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
+			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+					"WONT answered by DO");
+			break;
+		case Q_WANTNO_OP:
+			_set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
+			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+					"WONT answered by DO");
+			break;
+		case Q_WANTYES:
+			_set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
+			break;
+		case Q_WANTYES_OP:
+			_set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
+			_send_negotiate(telnet, TELNET_WONT, telopt);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
+			break;
+		}
+		break;
+
+	/* request to disable option on local end, confirm WONT, reject WILL */
+	case TELNET_STATE_DONT:
+		switch (Q_US(q)) {
+		case Q_YES:
+			_set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
+			_send_negotiate(telnet, TELNET_WONT, telopt);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
+			break;
+		case Q_WANTNO:
+			_set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
+			break;
+		case Q_WANTNO_OP:
+			_set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
+			_send_negotiate(telnet, TELNET_WILL, telopt);
+			NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
+			break;
+		case Q_WANTYES:
+		case Q_WANTYES_OP:
+			_set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
+			break;
+		}
+		break;
+	}
+}
+
+/* process an ENVIRON/NEW-ENVIRON subnegotiation buffer
+ *
+ * the algorithm and approach used here is kind of a hack,
+ * but it reduces the number of memory allocations we have
+ * to make.
+ *
+ * we copy the bytes back into the buffer, starting at the very
+ * beginning, which makes it easy to handle the ENVIRON ESC
+ * escape mechanism as well as ensure the variable name and
+ * value strings are NUL-terminated, all while fitting inside
+ * of the original buffer.
+ */
+static int _environ_telnet(telnet_t *telnet, unsigned char type,
+		char* buffer, size_t size) {
+	telnet_event_t ev;
+	struct telnet_environ_t *values = 0;
+	char *c, *last, *out;
+	size_t index, count;
+
+	/* if we have no data, just pass it through */
+	if (size == 0) {
+		return 0;
+	}
+
+	/* first byte must be a valid command */
+	if ((unsigned)buffer[0] != TELNET_ENVIRON_SEND &&
+			(unsigned)buffer[0] != TELNET_ENVIRON_IS && 
+			(unsigned)buffer[0] != TELNET_ENVIRON_INFO) {
+		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				"telopt %d subneg has invalid command", type);
+		return 0;
+	}
+
+	/* store ENVIRON command */
+	ev.environ.cmd = buffer[0];
+
+	/* if we have no arguments, send an event with no data end return */
+	if (size == 1) {
+		/* no list of variables given */
+		ev.environ.values = 0;
+		ev.environ.size = 0;
+
+		/* invoke event with our arguments */
+		ev.type = TELNET_EV_ENVIRON;
+		telnet->eh(telnet, &ev, telnet->ud);
+
+		return 1;
+	}
+
+	/* very second byte must be VAR or USERVAR, if present */
+	if ((unsigned)buffer[1] != TELNET_ENVIRON_VAR &&
+			(unsigned)buffer[1] != TELNET_ENVIRON_USERVAR) {
+		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				"telopt %d subneg missing variable type", type);
+		return 0;
+	}
+
+	/* ensure last byte is not an escape byte (makes parsing later easier) */
+	if ((unsigned)buffer[size - 1] == TELNET_ENVIRON_ESC) {
+		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				"telopt %d subneg ends with ESC", type);
+		return 0;
+	}
+
+	/* count arguments; each valid entry starts with VAR or USERVAR */
+	count = 0;
+	for (c = buffer + 1; c < buffer + size; ++c) {
+		if (*c == TELNET_ENVIRON_VAR || *c == TELNET_ENVIRON_USERVAR) {
+			++count;
+		} else if (*c == TELNET_ENVIRON_ESC) {
+			/* skip the next byte */
+			++c;
+		}
+	}
+
+	/* allocate argument array, bail on error */
+	if ((values = (struct telnet_environ_t *)calloc(count,
+			sizeof(struct telnet_environ_t))) == 0) {
+		_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+				"calloc() failed: %s", strerror(errno));
+		return 0;
+	}
+
+	/* parse argument array strings */
+	out = buffer;
+	c = buffer + 1;
+	for (index = 0; index != count; ++index) {
+		/* remember the variable type (will be VAR or USERVAR) */
+		values[index].type = *c++;
+
+		/* scan until we find an end-marker, and buffer up unescaped
+		 * bytes into our buffer */
+		last = out;
+		while (c < buffer + size) {
+			/* stop at the next variable or at the value */
+			if ((unsigned)*c == TELNET_ENVIRON_VAR ||
+					(unsigned)*c == TELNET_ENVIRON_VALUE ||
+					(unsigned)*c == TELNET_ENVIRON_USERVAR) {
+				break;
+			}
+
+			/* buffer next byte (taking into account ESC) */
+			if (*c == TELNET_ENVIRON_ESC) {
+				++c;
+			}
+
+			*out++ = *c++;
+		}
+		*out++ = '\0';
+
+		/* store the variable name we have just received */
+		values[index].var = last;
+		values[index].value = "";
+
+		/* if we got a value, find the next end marker and
+		 * store the value; otherwise, store empty string */
+		if (c < buffer + size && *c == TELNET_ENVIRON_VALUE) {
+			++c;
+			last = out;
+			while (c < buffer + size) {
+				/* stop when we find the start of the next variable */
+				if ((unsigned)*c == TELNET_ENVIRON_VAR ||
+						(unsigned)*c == TELNET_ENVIRON_USERVAR) {
+					break;
+				}
+
+				/* buffer next byte (taking into account ESC) */
+				if (*c == TELNET_ENVIRON_ESC) {
+					++c;
+				}
+
+				*out++ = *c++;
+			}
+			*out++ = '\0';
+
+			/* store the variable value */
+			values[index].value = last;
+		}
+	}
+
+	/* pass values array and count to event */
+	ev.environ.values = values;
+	ev.environ.size = count;
+
+	/* invoke event with our arguments */
+	ev.type = TELNET_EV_ENVIRON;
+	telnet->eh(telnet, &ev, telnet->ud);
+
+	/* clean up */
+	free(values);
+	return 1;
+}
+
+/* process an MSSP subnegotiation buffer */
+static int _mssp_telnet(telnet_t *telnet, char* buffer, size_t size) {
+	telnet_event_t ev;
+	struct telnet_environ_t *values;
+	char *var = 0;
+	char *c, *last, *out;
+	size_t i, count;
+	unsigned char next_type;
+
+	/* if we have no data, just pass it through */
+	if (size == 0) {
+		return 0;
+	}
+
+	/* first byte must be a VAR */
+	if ((unsigned)buffer[0] != TELNET_MSSP_VAR) {
+		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				"MSSP subnegotiation has invalid data");
+		return 0;
+	}
+
+	/* count the arguments, any part that starts with VALUE */
+	for (count = 0, i = 0; i != size; ++i) {
+		if ((unsigned)buffer[i] == TELNET_MSSP_VAL) {
+			++count;
+		}
+	}
+
+	/* allocate argument array, bail on error */
+	if ((values = (struct telnet_environ_t *)calloc(count,
+			sizeof(struct telnet_environ_t))) == 0) {
+		_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+				"calloc() failed: %s", strerror(errno));
+		return 0;
+	}
+
+	ev.mssp.values = values;
+	ev.mssp.size = count;
+
+	/* allocate strings in argument array */
+	out = last = buffer;
+	next_type = buffer[0];
+	for (i = 0, c = buffer + 1; c < buffer + size;) {
+		/* search for end marker */
+		while (c < buffer + size && (unsigned)*c != TELNET_MSSP_VAR &&
+				(unsigned)*c != TELNET_MSSP_VAL) {
+			*out++ = *c++;
+		}
+		*out++ = '\0';
+
+		/* if it's a variable name, just store the name for now */
+		if (next_type == TELNET_MSSP_VAR) {
+			var = last;
+		} else if (next_type == TELNET_MSSP_VAL && var != 0) {
+			values[i].var = var;
+			values[i].value = last;
+			++i;
+		} else {
+			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+					"invalid MSSP subnegotiation data");
+			free(values);
+			return 0;
+		}
+
+		/* remember our next type and increment c for next loop run */
+		last = out;
+		next_type = *c++;
+	}
+
+	/* invoke event with our arguments */
+	ev.type = TELNET_EV_MSSP;
+	telnet->eh(telnet, &ev, telnet->ud);
+
+	/* clean up */
+	free(values);
+
+	return 0;
+}
+
+/* parse ZMP command subnegotiation buffers */
+static int _zmp_telnet(telnet_t *telnet, const char* buffer, size_t size) {
+	telnet_event_t ev;
+	const char **argv;
+	const char *c;
+	size_t i, argc;
+
+	/* make sure this is a valid ZMP buffer */
+	if (size == 0 || buffer[size - 1] != 0) {
+		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				"incomplete ZMP frame");
+		return 0;
+	}
+
+	/* count arguments */
+	for (argc = 0, c = buffer; c != buffer + size; ++argc)
+		c += strlen(c) + 1;
+
+	/* allocate argument array, bail on error */
+	if ((argv = (const char **)calloc(argc, sizeof(char *))) == 0) {
+		_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+				"calloc() failed: %s", strerror(errno));
+		return 0;
+	}
+
+	/* populate argument array */
+	for (i = 0, c = buffer; i != argc; ++i) {
+		argv[i] = c;
+		c += strlen(c) + 1;
+	}
+
+	/* invoke event with our arguments */
+	ev.type = TELNET_EV_ZMP;
+	ev.zmp.argv = argv;
+	ev.zmp.argc = argc;
+	telnet->eh(telnet, &ev, telnet->ud);
+
+	/* clean up */
+	free(argv);
+	return 0;
+}
+
+/* parse TERMINAL-TYPE command subnegotiation buffers */
+static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) {
+	telnet_event_t ev;
+
+	/* make sure request is not empty */
+	if (size == 0) {
+		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				"incomplete TERMINAL-TYPE request");
+		return 0;
+	}
+
+	/* make sure request has valid command type */
+	if (buffer[0] != TELNET_TTYPE_IS &&
+			buffer[0] != TELNET_TTYPE_SEND) {
+		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				"TERMINAL-TYPE request has invalid type");
+		return 0;
+	}
+
+	/* send proper event */
+	if (buffer[0] == TELNET_TTYPE_IS) {
+		char *name;
+
+		/* allocate space for name */
+		if ((name = (char *)malloc(size)) == 0) {
+			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+					"malloc() failed: %s", strerror(errno));
+			return 0;
+		}
+		memcpy(name, buffer + 1, size - 1);
+		name[size - 1] = '\0';
+
+		ev.type = TELNET_EV_TTYPE;
+		ev.ttype.cmd = TELNET_TTYPE_IS;
+		ev.ttype.name = name;
+		telnet->eh(telnet, &ev, telnet->ud);
+
+		/* clean up */
+		free(name);
+	} else {
+		ev.type = TELNET_EV_TTYPE;
+		ev.ttype.cmd = TELNET_TTYPE_SEND;
+		ev.ttype.name = 0;
+		telnet->eh(telnet, &ev, telnet->ud);
+	}
+
+	return 0;
+}
+
+/* process a subnegotiation buffer; return non-zero if the current buffer
+ * must be aborted and reprocessed due to COMPRESS2 being activated
+ */
+static int _subnegotiate(telnet_t *telnet) {
+	telnet_event_t ev;
+
+	/* standard subnegotiation event */
+	ev.type = TELNET_EV_SUBNEGOTIATION;
+	ev.sub.telopt = telnet->sb_telopt;
+	ev.sub.buffer = telnet->buffer;
+	ev.sub.size = telnet->buffer_pos;
+	telnet->eh(telnet, &ev, telnet->ud);
+
+	switch (telnet->sb_telopt) {
+#if defined(HAVE_ZLIB)
+	/* received COMPRESS2 begin marker, setup our zlib box and
+	 * start handling the compressed stream if it's not already.
+	 */
+	case TELNET_TELOPT_COMPRESS2:
+		if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) {
+			if (_init_zlib(telnet, 0, 1) != TELNET_EOK)
+				return 0;
+
+			/* notify app that compression was enabled */
+			ev.type = TELNET_EV_COMPRESS;
+			ev.compress.state = 1;
+			telnet->eh(telnet, &ev, telnet->ud);
+			return 1;
+		}
+		return 0;
+#endif /* defined(HAVE_ZLIB) */
+
+	/* specially handled subnegotiation telopt types */
+	case TELNET_TELOPT_ZMP:
+		return _zmp_telnet(telnet, telnet->buffer, telnet->buffer_pos);
+	case TELNET_TELOPT_TTYPE:
+		return _ttype_telnet(telnet, telnet->buffer, telnet->buffer_pos);
+	case TELNET_TELOPT_ENVIRON:
+	case TELNET_TELOPT_NEW_ENVIRON:
+		return _environ_telnet(telnet, telnet->sb_telopt, telnet->buffer,
+				telnet->buffer_pos);
+	case TELNET_TELOPT_MSSP:
+		return _mssp_telnet(telnet, telnet->buffer, telnet->buffer_pos);
+	default:
+		return 0;
+	}
+}
+
+/* initialize a telnet state tracker */
+telnet_t *telnet_init(const telnet_telopt_t *telopts,
+		telnet_event_handler_t eh, unsigned char flags, void *user_data) {
+	/* allocate structure */
+	struct telnet_t *telnet = (telnet_t*)calloc(1, sizeof(telnet_t));
+	if (telnet == 0)
+		return 0;
+
+	/* initialize data */
+	telnet->ud = user_data;
+	telnet->telopts = telopts;
+	telnet->eh = eh;
+	telnet->flags = flags;
+
+	return telnet;
+}
+
+/* free up any memory allocated by a state tracker */
+void telnet_free(telnet_t *telnet) {
+	/* free sub-request buffer */
+	if (telnet->buffer != 0) {
+		free(telnet->buffer);
+		telnet->buffer = 0;
+		telnet->buffer_size = 0;
+		telnet->buffer_pos = 0;
+	}
+
+#if defined(HAVE_ZLIB)
+	/* free zlib box */
+	if (telnet->z != 0) {
+		if (telnet->flags & TELNET_PFLAG_DEFLATE)
+			deflateEnd(telnet->z);
+		else
+			inflateEnd(telnet->z);
+		free(telnet->z);
+		telnet->z = 0;
+	}
+#endif /* defined(HAVE_ZLIB) */
+
+	/* free RFC1143 queue */
+	if (telnet->q) {
+		free(telnet->q);
+		telnet->q = 0;
+		telnet->q_size = 0;
+	}
+
+	/* free the telnet structure itself */
+	free(telnet);
+}
+
+/* push a byte into the telnet buffer */
+static telnet_error_t _buffer_byte(telnet_t *telnet,
+		unsigned char byte) {
+	char *new_buffer;
+	size_t i;
+
+	/* check if we're out of room */
+	if (telnet->buffer_pos == telnet->buffer_size) {
+		/* find the next buffer size */
+		for (i = 0; i != _buffer_sizes_count; ++i) {
+			if (_buffer_sizes[i] == telnet->buffer_size) {
+				break;
+			}
+		}
+
+		/* overflow -- can't grow any more */
+		if (i >= _buffer_sizes_count - 1) {
+			_error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
+					"subnegotiation buffer size limit reached");
+			return TELNET_EOVERFLOW;
+		}
+
+		/* (re)allocate buffer */
+		new_buffer = (char *)realloc(telnet->buffer, _buffer_sizes[i + 1]);
+		if (new_buffer == 0) {
+			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+					"realloc() failed");
+			return TELNET_ENOMEM;
+		}
+
+		telnet->buffer = new_buffer;
+		telnet->buffer_size = _buffer_sizes[i + 1];
+	}
+
+	/* push the byte, all set */
+	telnet->buffer[telnet->buffer_pos++] = byte;
+	return TELNET_EOK;
+}
+
+static void _process(telnet_t *telnet, const char *buffer, size_t size) {
+	telnet_event_t ev;
+	unsigned char byte;
+	size_t i, start;
+	for (i = start = 0; i != size; ++i) {
+		byte = buffer[i];
+		switch (telnet->state) {
+		/* regular data */
+		case TELNET_STATE_DATA:
+			/* on an IAC byte, pass through all pending bytes and
+			 * switch states */
+			if (byte == TELNET_IAC) {
+				if (i != start) {
+					ev.type = TELNET_EV_DATA;
+					ev.data.buffer = buffer + start;
+					ev.data.size = i - start;
+					telnet->eh(telnet, &ev, telnet->ud);
+				}
+				telnet->state = TELNET_STATE_IAC;
+			}
+			break;
+
+		/* IAC command */
+		case TELNET_STATE_IAC:
+			switch (byte) {
+			/* subnegotiation */
+			case TELNET_SB:
+				telnet->state = TELNET_STATE_SB;
+				break;
+			/* negotiation commands */
+			case TELNET_WILL:
+				telnet->state = TELNET_STATE_WILL;
+				break;
+			case TELNET_WONT:
+				telnet->state = TELNET_STATE_WONT;
+				break;
+			case TELNET_DO:
+				telnet->state = TELNET_STATE_DO;
+				break;
+			case TELNET_DONT:
+				telnet->state = TELNET_STATE_DONT;
+				break;
+			/* IAC escaping */
+			case TELNET_IAC:
+				/* event */
+				ev.type = TELNET_EV_DATA;
+				ev.data.buffer = (char*)&byte;
+				ev.data.size = 1;
+				telnet->eh(telnet, &ev, telnet->ud);
+
+				/* state update */
+				start = i + 1;
+				telnet->state = TELNET_STATE_DATA;
+				break;
+			/* some other command */
+			default:
+				/* event */
+				ev.type = TELNET_EV_IAC;
+				ev.iac.cmd = byte;
+				telnet->eh(telnet, &ev, telnet->ud);
+
+				/* state update */
+				start = i + 1;
+				telnet->state = TELNET_STATE_DATA;
+			}
+			break;
+
+		/* negotiation commands */
+		case TELNET_STATE_WILL:
+		case TELNET_STATE_WONT:
+		case TELNET_STATE_DO:
+		case TELNET_STATE_DONT:
+			_negotiate(telnet, byte);
+			start = i + 1;
+			telnet->state = TELNET_STATE_DATA;
+			break;
+
+		/* subnegotiation -- determine subnegotiation telopt */
+		case TELNET_STATE_SB:
+			telnet->sb_telopt = byte;
+			telnet->buffer_pos = 0;
+			telnet->state = TELNET_STATE_SB_DATA;
+			break;
+
+		/* subnegotiation -- buffer bytes until end request */
+		case TELNET_STATE_SB_DATA:
+			/* IAC command in subnegotiation -- either IAC SE or IAC IAC */
+			if (byte == TELNET_IAC) {
+				telnet->state = TELNET_STATE_SB_DATA_IAC;
+			/* buffer the byte, or bail if we can't */
+			} else if (_buffer_byte(telnet, byte) != TELNET_EOK) {
+				start = i + 1;
+				telnet->state = TELNET_STATE_DATA;
+			}
+			break;
+
+		/* IAC escaping inside a subnegotiation */
+		case TELNET_STATE_SB_DATA_IAC:
+			switch (byte) {
+			/* end subnegotiation */
+			case TELNET_SE:
+				/* return to default state */
+				start = i + 1;
+				telnet->state = TELNET_STATE_DATA;
+
+				/* process subnegotiation */
+				if (_subnegotiate(telnet) != 0) {
+					/* any remaining bytes in the buffer are compressed.
+					 * we have to re-invoke telnet_recv to get those
+					 * bytes inflated and abort trying to process the
+					 * remaining compressed bytes in the current _process
+					 * buffer argument
+					 */
+					telnet_recv(telnet, &buffer[start], size - start);
+					return;
+				}
+				break;
+			/* escaped IAC byte */
+			case TELNET_IAC:
+				/* push IAC into buffer */
+				if (_buffer_byte(telnet, TELNET_IAC) !=
+						TELNET_EOK) {
+					start = i + 1;
+					telnet->state = TELNET_STATE_DATA;
+				} else {
+					telnet->state = TELNET_STATE_SB_DATA;
+				}
+				break;
+			/* something else -- protocol error.  attempt to process
+			 * content in subnegotiation buffer, then evaluate the
+			 * given command as an IAC code.
+			 */
+			default:
+				_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+						"unexpected byte after IAC inside SB: %d",
+						byte);
+
+				/* enter IAC state */
+				start = i + 1;
+				telnet->state = TELNET_STATE_IAC;
+
+				/* process subnegotiation; see comment in
+				 * TELNET_STATE_SB_DATA_IAC about invoking telnet_recv()
+				 */
+				if (_subnegotiate(telnet) != 0) {
+					telnet_recv(telnet, &buffer[start], size - start);
+					return;
+				} else {
+					/* recursive call to get the current input byte processed
+					 * as a regular IAC command.  we could use a goto, but
+					 * that would be gross.
+					 */
+					_process(telnet, (char *)&byte, 1);
+				}
+				break;
+			}
+			break;
+		}
+	}
+
+	/* pass through any remaining bytes */ 
+	if (telnet->state == TELNET_STATE_DATA && i != start) {
+		ev.type = TELNET_EV_DATA;
+		ev.data.buffer = buffer + start;
+		ev.data.size = i - start;
+		telnet->eh(telnet, &ev, telnet->ud);
+	}
+}
+
+/* push a bytes into the state tracker */
+void telnet_recv(telnet_t *telnet, const char *buffer,
+		size_t size) {
+#if defined(HAVE_ZLIB)
+	/* if we have an inflate (decompression) zlib stream, use it */
+	if (telnet->z != 0 && !(telnet->flags & TELNET_PFLAG_DEFLATE)) {
+		char inflate_buffer[1024];
+		int rs;
+
+		/* initialize zlib state */
+		telnet->z->next_in = (unsigned char*)buffer;
+		telnet->z->avail_in = size;
+		telnet->z->next_out = (unsigned char *)inflate_buffer;
+		telnet->z->avail_out = sizeof(inflate_buffer);
+
+		/* inflate until buffer exhausted and all output is produced */
+		while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
+			/* reset output buffer */
+
+			/* decompress */
+			rs = inflate(telnet->z, Z_SYNC_FLUSH);
+
+			/* process the decompressed bytes on success */
+			if (rs == Z_OK || rs == Z_STREAM_END)
+				_process(telnet, inflate_buffer, sizeof(inflate_buffer) -
+						telnet->z->avail_out);
+			else
+				_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
+						"inflate() failed: %s", zError(rs));
+
+			/* prepare output buffer for next run */
+			telnet->z->next_out = (unsigned char *)inflate_buffer;
+			telnet->z->avail_out = sizeof(inflate_buffer);
+
+			/* on error (or on end of stream) disable further inflation */
+			if (rs != Z_OK) {
+				telnet_event_t ev;
+
+				/* disable compression */
+				inflateEnd(telnet->z);
+				free(telnet->z);
+				telnet->z = 0;
+
+				/* send event */
+				ev.type = TELNET_EV_COMPRESS;
+				ev.compress.state = 0;
+				telnet->eh(telnet, &ev, telnet->ud);
+
+				break;
+			}
+		}
+
+	/* COMPRESS2 is not negotiated, just process */
+	} else
+#endif /* defined(HAVE_ZLIB) */
+		_process(telnet, buffer, size);
+}
+
+/* send an iac command */
+void telnet_iac(telnet_t *telnet, unsigned char cmd) {
+	unsigned char bytes[2];
+	bytes[0] = TELNET_IAC;
+	bytes[1] = cmd;
+	_sendu(telnet, bytes, 2);
+}
+
+/* send negotiation */
+void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
+		unsigned char telopt) {
+	telnet_rfc1143_t q;
+
+	/* if we're in proxy mode, just send it now */
+	if (telnet->flags & TELNET_FLAG_PROXY) {
+		unsigned char bytes[3];
+		bytes[0] = TELNET_IAC;
+		bytes[1] = cmd;
+		bytes[2] = telopt;
+		_sendu(telnet, bytes, 3);
+		return;
+	}
+	
+	/* get current option states */
+	q = _get_rfc1143(telnet, telopt);
+
+	switch (cmd) {
+	/* advertise willingess to support an option */
+	case TELNET_WILL:
+		switch (Q_US(q)) {
+		case Q_NO:
+			_set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
+			_send_negotiate(telnet, TELNET_WILL, telopt);
+			break;
+		case Q_WANTNO:
+			_set_rfc1143(telnet, telopt, Q_WANTNO_OP, Q_HIM(q));
+			break;
+		case Q_WANTYES_OP:
+			_set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
+			break;
+		}
+		break;
+
+	/* force turn-off of locally enabled option */
+	case TELNET_WONT:
+		switch (Q_US(q)) {
+		case Q_YES:
+			_set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
+			_send_negotiate(telnet, TELNET_WONT, telopt);
+			break;
+		case Q_WANTYES:
+			_set_rfc1143(telnet, telopt, Q_WANTYES_OP, Q_HIM(q));
+			break;
+		case Q_WANTNO_OP:
+			_set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
+			break;
+		}
+		break;
+
+	/* ask remote end to enable an option */
+	case TELNET_DO:
+		switch (Q_HIM(q)) {
+		case Q_NO:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
+			_send_negotiate(telnet, TELNET_DO, telopt);
+			break;
+		case Q_WANTNO:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO_OP);
+			break;
+		case Q_WANTYES_OP:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
+			break;
+		}
+		break;
+
+	/* demand remote end disable an option */
+	case TELNET_DONT:
+		switch (Q_HIM(q)) {
+		case Q_YES:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
+			_send_negotiate(telnet, TELNET_DONT, telopt);
+			break;
+		case Q_WANTYES:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES_OP);
+			break;
+		case Q_WANTNO_OP:
+			_set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
+			break;
+		}
+		break;
+	}
+}
+
+/* send non-command data (escapes IAC bytes) */
+void telnet_send(telnet_t *telnet, const char *buffer,
+		size_t size) {
+	size_t i, l;
+
+	for (l = i = 0; i != size; ++i) {
+		/* dump prior portion of text, send escaped bytes */
+		if (buffer[i] == (char)TELNET_IAC) {
+			/* dump prior text if any */
+			if (i != l) {
+				_send(telnet, buffer + l, i - l);
+			}
+			l = i + 1;
+
+			/* send escape */
+			telnet_iac(telnet, TELNET_IAC);
+		}
+	}
+
+	/* send whatever portion of buffer is left */
+	if (i != l) {
+		_send(telnet, buffer + l, i - l);
+	}
+}
+
+/* send subnegotiation header */
+void telnet_begin_sb(telnet_t *telnet, unsigned char telopt) {
+	unsigned char sb[3];
+	sb[0] = TELNET_IAC;
+	sb[1] = TELNET_SB;
+	sb[2] = telopt;
+	_sendu(telnet, sb, 3);
+}
+
+
+/* send complete subnegotiation */
+void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt,
+		const char *buffer, size_t size) {
+	unsigned char bytes[5];
+	bytes[0] = TELNET_IAC;
+	bytes[1] = TELNET_SB;
+	bytes[2] = telopt;
+	bytes[3] = TELNET_IAC;
+	bytes[4] = TELNET_SE;
+
+	_sendu(telnet, bytes, 3);
+	telnet_send(telnet, buffer, size);
+	_sendu(telnet, bytes + 3, 2);
+
+#if defined(HAVE_ZLIB)
+	/* if we're a proxy and we just sent the COMPRESS2 marker, we must
+	 * make sure all further data is compressed if not already.
+	 */
+	if (telnet->flags & TELNET_FLAG_PROXY &&
+			telopt == TELNET_TELOPT_COMPRESS2) {
+		telnet_event_t ev;
+
+		if (_init_zlib(telnet, 1, 1) != TELNET_EOK)
+			return;
+
+		/* notify app that compression was enabled */
+		ev.type = TELNET_EV_COMPRESS;
+		ev.compress.state = 1;
+		telnet->eh(telnet, &ev, telnet->ud);
+	}
+#endif /* defined(HAVE_ZLIB) */
+}
+
+void telnet_begin_compress2(telnet_t *telnet) {
+	UNUSED_ARG(telnet);
+#if defined(HAVE_ZLIB)
+	static const unsigned char compress2[] = { TELNET_IAC, TELNET_SB,
+			TELNET_TELOPT_COMPRESS2, TELNET_IAC, TELNET_SE };
+
+	telnet_event_t ev;
+
+	/* attempt to create output stream first, bail if we can't */
+	if (_init_zlib(telnet, 1, 0) != TELNET_EOK)
+		return;
+
+	/* send compression marker.  we send directly to the event handler
+	 * instead of passing through _send because _send would result in
+	 * the compress marker itself being compressed.
+	 */
+	ev.type = TELNET_EV_SEND;
+	ev.data.buffer = (const char*)compress2;
+	ev.data.size = sizeof(compress2);
+	telnet->eh(telnet, &ev, telnet->ud);
+
+	/* notify app that compression was successfully enabled */
+	ev.type = TELNET_EV_COMPRESS;
+	ev.compress.state = 1;
+	telnet->eh(telnet, &ev, telnet->ud);
+#endif /* defined(HAVE_ZLIB) */
+}
+
+/* send formatted data with \r and \n translation in addition to IAC IAC */
+int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
+    static const char CRLF[] = { '\r', '\n' };
+    static const char CRNUL[] = { '\r', '\0' };
+	char buffer[1024];
+	char *output = buffer;
+	int rs, i, l;
+
+	/* format */
+	rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
+	if ((size_t)rs >= sizeof(buffer)) {
+		output = (char*)malloc(rs + 1);
+		if (output == 0) {
+			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+					"malloc() failed: %s", strerror(errno));
+			return -1;
+		}
+		rs = vsnprintf(output, rs + 1, fmt, va);
+	}
+
+	/* send */
+	for (l = i = 0; i != rs; ++i) {
+		/* special characters */
+		if (output[i] == (char)TELNET_IAC || output[i] == '\r' ||
+				output[i] == '\n') {
+			/* dump prior portion of text */
+			if (i != l)
+				_send(telnet, output + l, i - l);
+			l = i + 1;
+
+			/* IAC -> IAC IAC */
+			if (output[i] == (char)TELNET_IAC)
+				telnet_iac(telnet, TELNET_IAC);
+			/* automatic translation of \r -> CRNUL */
+			else if (output[i] == '\r')
+				_send(telnet, CRNUL, 2);
+			/* automatic translation of \n -> CRLF */
+			else if (output[i] == '\n')
+				_send(telnet, CRLF, 2);
+		}
+	}
+
+	/* send whatever portion of output is left */
+	if (i != l) {
+		_send(telnet, output + l, i - l);
+	}
+
+	/* free allocated memory, if any */
+	if (output != buffer) {
+		free(output);
+	}
+
+	return rs;
+}
+
+/* see telnet_vprintf */
+int telnet_printf(telnet_t *telnet, const char *fmt, ...) {
+	va_list va;
+	int rs;
+
+	va_start(va, fmt);
+	rs = telnet_vprintf(telnet, fmt, va);
+	va_end(va);
+
+	return rs;
+}
+
+/* send formatted data through telnet_send */
+int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
+	char buffer[1024];
+	char *output = buffer;
+	int rs;
+
+	/* format; allocate more space if necessary */
+	rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
+	if ((size_t)rs >= sizeof(buffer)) {
+		output = (char*)malloc(rs + 1);
+		if (output == 0) {
+			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+					"malloc() failed: %s", strerror(errno));
+			return -1;
+		}
+		rs = vsnprintf(output, rs + 1, fmt, va);
+	}
+
+	/* send out the formatted data */
+	telnet_send(telnet, output, rs);
+
+	/* release allocated memory, if any */
+	if (output != buffer) {
+		free(output);
+	}
+
+	return rs;
+}
+
+/* see telnet_raw_vprintf */
+int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...) {
+	va_list va;
+	int rs;
+
+	va_start(va, fmt);
+	rs = telnet_raw_vprintf(telnet, fmt, va);
+	va_end(va);
+
+	return rs;
+}
+
+/* begin NEW-ENVIRON subnegotation */
+void telnet_begin_newenviron(telnet_t *telnet, unsigned char cmd) {
+	telnet_begin_sb(telnet, TELNET_TELOPT_NEW_ENVIRON);
+	telnet_send(telnet, (char*)&cmd, 1);
+}
+
+/* send a NEW-ENVIRON value */
+void telnet_newenviron_value(telnet_t *telnet, unsigned char type,
+		const char *string) {
+	telnet_send(telnet, (char*)&type, 1);
+
+	if (string != 0) {
+		telnet_send(telnet, string, strlen(string));
+	}
+}
+
+/* send TERMINAL-TYPE SEND command */
+void telnet_ttype_send(telnet_t *telnet) {
+    static const unsigned char SEND[] = { TELNET_IAC, TELNET_SB,
+			TELNET_TELOPT_TTYPE, TELNET_TTYPE_SEND, TELNET_IAC, TELNET_SE };
+	_sendu(telnet, SEND, sizeof(SEND));
+}
+
+/* send TERMINAL-TYPE IS command */
+void telnet_ttype_is(telnet_t *telnet, const char* ttype) {
+	static const unsigned char IS[] = { TELNET_IAC, TELNET_SB,
+			TELNET_TELOPT_TTYPE, TELNET_TTYPE_IS };
+	_sendu(telnet, IS, sizeof(IS));
+	_send(telnet, ttype, strlen(ttype));
+	telnet_finish_sb(telnet);
+}
+
+/* send ZMP data */
+void telnet_send_zmp(telnet_t *telnet, size_t argc, const char **argv) {
+	size_t i;
+
+	/* ZMP header */
+	telnet_begin_zmp(telnet, argv[0]);
+
+	/* send out each argument, including trailing NUL byte */
+	for (i = 1; i != argc; ++i)
+		telnet_zmp_arg(telnet, argv[i]);
+
+	/* ZMP footer */
+	telnet_finish_zmp(telnet);
+}
+
+/* send ZMP data using varargs  */
+void telnet_send_vzmpv(telnet_t *telnet, va_list va) {
+	const char* arg;
+
+	/* ZMP header */
+	telnet_begin_sb(telnet, TELNET_TELOPT_ZMP);
+
+	/* send out each argument, including trailing NUL byte */
+	while ((arg = va_arg(va, const char *)) != 0)
+		telnet_zmp_arg(telnet, arg);
+
+	/* ZMP footer */
+	telnet_finish_zmp(telnet);
+}
+
+/* see telnet_send_vzmpv */
+void telnet_send_zmpv(telnet_t *telnet, ...) {
+	va_list va;
+
+	va_start(va, telnet);
+	telnet_send_vzmpv(telnet, va);
+	va_end(va);
+}
+
+/* begin a ZMP command */
+void telnet_begin_zmp(telnet_t *telnet, const char *cmd) {
+	telnet_begin_sb(telnet, TELNET_TELOPT_ZMP);
+	telnet_zmp_arg(telnet, cmd);
+}
+
+/* send a ZMP argument */
+void telnet_zmp_arg(telnet_t *telnet, const char* arg) {
+	telnet_send(telnet, arg, strlen(arg) + 1);
+}

+ 677 - 0
src/apps/relay/libtelnet.h

@@ -0,0 +1,677 @@
+/*!
+ * \brief libtelnet - TELNET protocol handling library
+ *
+ * SUMMARY:
+ *
+ * libtelnet is a library for handling the TELNET protocol.  It includes
+ * routines for parsing incoming data from a remote peer as well as formatting
+ * data to send to the remote peer.
+ *
+ * libtelnet uses a callback-oriented API, allowing application-specific
+ * handling of various events.  The callback system is also used for buffering
+ * outgoing protocol data, allowing the application to maintain control over
+ * the actual socket connection.
+ *
+ * Features supported include the full TELNET protocol, Q-method option
+ * negotiation, ZMP, MCCP2, MSSP, and NEW-ENVIRON.
+ *
+ * CONFORMS TO:
+ *
+ * RFC854  - http://www.faqs.org/rfcs/rfc854.html
+ * RFC855  - http://www.faqs.org/rfcs/rfc855.html
+ * RFC1091 - http://www.faqs.org/rfcs/rfc1091.html
+ * RFC1143 - http://www.faqs.org/rfcs/rfc1143.html
+ * RFC1408 - http://www.faqs.org/rfcs/rfc1408.html
+ * RFC1572 - http://www.faqs.org/rfcs/rfc1572.html
+ *
+ * LICENSE:
+ *
+ * The author or authors of this code dedicate any and all copyright interest
+ * in this code to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and successors. We
+ * intend this dedication to be an overt act of relinquishment in perpetuity of
+ * all present and future rights to this code under copyright law.
+ *
+ * \file libtelnet.h
+ *
+ * \version 0.21
+ *
+ * \author Sean Middleditch <[email protected]>
+ */
+
+/**
+ * Minor fixes by Oleg Moskalenko
+ */
+
+#if !defined(LIBTELNET_INCLUDE)
+#define LIBTELNET_INCLUDE 1
+
+/* standard C headers necessary for the libtelnet API */
+#include <stdarg.h>
+
+/* C++ support */
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* printf type checking feature in GCC and some other compilers */
+#if __GNUC__
+# define TELNET_GNU_PRINTF(f,a) __attribute__((format(printf, f, a))) /*!< internal helper */
+#else
+# define TELNET_GNU_PRINTF(f,a) /*!< internal helper */
+#endif
+
+/*! Telnet state tracker object type. */
+typedef struct telnet_t telnet_t;
+
+/*! Telnet event object type. */
+typedef union telnet_event_t telnet_event_t;
+
+/*! Telnet option table element type. */
+typedef struct telnet_telopt_t telnet_telopt_t;
+
+/*! \name Telnet commands */
+/*@{*/
+/*! Telnet commands and special values. */
+#define TELNET_IAC 255
+#define TELNET_DONT 254
+#define TELNET_DO 253
+#define TELNET_WONT 252
+#define TELNET_WILL 251
+#define TELNET_SB 250
+#define TELNET_GA 249
+#define TELNET_EL 248
+#define TELNET_EC 247
+#define TELNET_AYT 246
+#define TELNET_AO 245
+#define TELNET_IP 244
+#define TELNET_BREAK 243
+#define TELNET_DM 242
+#define TELNET_NOP 241
+#define TELNET_SE 240
+#define TELNET_EOR 239
+#define TELNET_ABORT 238
+#define TELNET_SUSP 237
+#define TELNET_EOF 236
+/*@}*/
+
+/*! \name Telnet option values. */
+/*@{*/
+/*! Telnet options. */
+#define TELNET_TELOPT_BINARY 0
+#define TELNET_TELOPT_ECHO 1
+#define TELNET_TELOPT_RCP 2
+#define TELNET_TELOPT_SGA 3
+#define TELNET_TELOPT_NAMS 4
+#define TELNET_TELOPT_STATUS 5
+#define TELNET_TELOPT_TM 6
+#define TELNET_TELOPT_RCTE 7
+#define TELNET_TELOPT_NAOL 8
+#define TELNET_TELOPT_NAOP 9
+#define TELNET_TELOPT_NAOCRD 10
+#define TELNET_TELOPT_NAOHTS 11
+#define TELNET_TELOPT_NAOHTD 12
+#define TELNET_TELOPT_NAOFFD 13
+#define TELNET_TELOPT_NAOVTS 14
+#define TELNET_TELOPT_NAOVTD 15
+#define TELNET_TELOPT_NAOLFD 16
+#define TELNET_TELOPT_XASCII 17
+#define TELNET_TELOPT_LOGOUT 18
+#define TELNET_TELOPT_BM 19
+#define TELNET_TELOPT_DET 20
+#define TELNET_TELOPT_SUPDUP 21
+#define TELNET_TELOPT_SUPDUPOUTPUT 22
+#define TELNET_TELOPT_SNDLOC 23
+#define TELNET_TELOPT_TTYPE 24
+#define TELNET_TELOPT_EOR 25
+#define TELNET_TELOPT_TUID 26
+#define TELNET_TELOPT_OUTMRK 27
+#define TELNET_TELOPT_TTYLOC 28
+#define TELNET_TELOPT_3270REGIME 29
+#define TELNET_TELOPT_X3PAD 30
+#define TELNET_TELOPT_NAWS 31
+#define TELNET_TELOPT_TSPEED 32
+#define TELNET_TELOPT_LFLOW 33
+#define TELNET_TELOPT_LINEMODE 34
+#define TELNET_TELOPT_XDISPLOC 35
+#define TELNET_TELOPT_ENVIRON 36
+#define TELNET_TELOPT_AUTHENTICATION 37
+#define TELNET_TELOPT_ENCRYPT 38
+#define TELNET_TELOPT_NEW_ENVIRON 39
+#define TELNET_TELOPT_MSSP 70
+#define TELNET_TELOPT_COMPRESS2 86
+#define TELNET_TELOPT_ZMP 93
+#define TELNET_TELOPT_EXOPL 255
+
+#define TELNET_TELOPT_MCCP2 86
+/*@}*/
+
+/*! \name Protocol codes for TERMINAL-TYPE commands. */
+/*@{*/
+/*! TERMINAL-TYPE codes. */
+#define TELNET_TTYPE_IS 0
+#define TELNET_TTYPE_SEND 1
+/*@}*/
+
+/*! \name Protocol codes for NEW-ENVIRON/ENVIRON commands. */
+/*@{*/
+/*! NEW-ENVIRON/ENVIRON codes. */
+#define TELNET_ENVIRON_IS 0
+#define TELNET_ENVIRON_SEND 1
+#define TELNET_ENVIRON_INFO 2
+#define TELNET_ENVIRON_VAR 0
+#define TELNET_ENVIRON_VALUE 1
+#define TELNET_ENVIRON_ESC 2
+#define TELNET_ENVIRON_USERVAR 3
+/*@}*/
+
+/*! \name Protocol codes for MSSP commands. */
+/*@{*/
+/*! MSSP codes. */
+#define TELNET_MSSP_VAR 1
+#define TELNET_MSSP_VAL 2
+/*@}*/
+
+/*! \name Telnet state tracker flags. */
+/*@{*/
+/*! Control behavior of telnet state tracker. */
+#define TELNET_FLAG_PROXY (1<<0)
+
+#define TELNET_PFLAG_DEFLATE (1<<7)
+/*@}*/
+
+#if !defined(UNUSED_ARG)
+#define UNUSED_ARG(A) do { A=A; } while(0)
+#endif
+
+/*! 
+ * error codes 
+ */
+enum telnet_error_t {
+	TELNET_EOK = 0,   /*!< no error */
+	TELNET_EBADVAL,   /*!< invalid parameter, or API misuse */
+	TELNET_ENOMEM,    /*!< memory allocation failure */
+	TELNET_EOVERFLOW, /*!< data exceeds buffer size */
+	TELNET_EPROTOCOL, /*!< invalid sequence of special bytes */
+	TELNET_ECOMPRESS  /*!< error handling compressed streams */
+};
+typedef enum telnet_error_t telnet_error_t; /*!< Error code type. */
+
+/*! 
+ * event codes 
+ */
+enum telnet_event_type_t {
+	TELNET_EV_DATA = 0,        /*!< raw text data has been received */
+	TELNET_EV_SEND,            /*!< data needs to be sent to the peer */
+	TELNET_EV_IAC,             /*!< generic IAC code received */
+	TELNET_EV_WILL,            /*!< WILL option negotiation received */
+	TELNET_EV_WONT,            /*!< WONT option neogitation received */
+	TELNET_EV_DO,              /*!< DO option negotiation received */
+	TELNET_EV_DONT,            /*!< DONT option negotiation received */
+	TELNET_EV_SUBNEGOTIATION,  /*!< sub-negotiation data received */
+	TELNET_EV_COMPRESS,        /*!< compression has been enabled */
+	TELNET_EV_ZMP,             /*!< ZMP command has been received */
+	TELNET_EV_TTYPE,           /*!< TTYPE command has been received */
+	TELNET_EV_ENVIRON,         /*!< ENVIRON command has been received */
+	TELNET_EV_MSSP,            /*!< MSSP command has been received */
+	TELNET_EV_WARNING,         /*!< recoverable error has occured */
+	TELNET_EV_ERROR            /*!< non-recoverable error has occured */
+};
+typedef enum telnet_event_type_t telnet_event_type_t; /*!< Telnet event type. */
+
+/*! 
+ * environ/MSSP command information 
+ */
+struct telnet_environ_t {
+	unsigned char type; /*!< either TELNET_ENVIRON_VAR or TELNET_ENVIRON_USERVAR */
+	const char *var;          /*!< name of the variable being set */
+	const char *value;        /*!< value of variable being set; empty string if no value */
+};
+
+/*! 
+ * event information 
+ */
+union telnet_event_t {
+	/*! 
+	 * \brief Event type
+	 *
+	 * The type field will determine which of the other event structure fields
+	 * have been filled in.  For instance, if the event type is TELNET_EV_ZMP,
+	 * then the zmp event field (and ONLY the zmp event field) will be filled
+	 * in.
+	 */ 
+	enum telnet_event_type_t type;
+
+	/*! 
+	 * data event: for DATA and SEND events 
+	 */
+	struct data_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		const char *buffer;             /*!< byte buffer */
+		size_t size;                    /*!< number of bytes in buffer */
+	} data;
+
+	/*! 
+	 * WARNING and ERROR events 
+	 */
+	struct error_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		const char *file;               /*!< file the error occured in */
+		const char *func;               /*!< function the error occured in */
+		const char *msg;                /*!< error message string */
+		int line;                       /*!< line of file error occured on */
+		telnet_error_t errcode;         /*!< error code */
+	} error;
+
+	/*! 
+	 * command event: for IAC 
+	 */
+	struct iac_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		unsigned char cmd;              /*!< telnet command received */
+	} iac;
+
+	/*! 
+	 * negotiation event: WILL, WONT, DO, DONT 
+	 */
+	struct negotiate_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		unsigned char telopt;           /*!< option being negotiated */
+	} neg;
+
+	/*! 
+	 * subnegotiation event 
+	 */
+	struct subnegotiate_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		const char *buffer;             /*!< data of sub-negotiation */
+		size_t size;                    /*!< number of bytes in buffer */
+		unsigned char telopt;           /*!< option code for negotiation */
+	} sub;
+
+	/*! 
+	 * ZMP event 
+	 */
+	struct zmp_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		const char **argv;              /*!< array of argument string */
+		size_t argc;                    /*!< number of elements in argv */
+	} zmp;
+
+	/*! 
+	 * TTYPE event 
+	 */
+	struct ttype_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		unsigned char cmd;              /*!< TELNET_TTYPE_IS or TELNET_TTYPE_SEND */
+		const char* name;               /*!< terminal type name (IS only) */
+	} ttype;
+
+	/*! 
+	 * COMPRESS event 
+	 */
+	struct compress_t {
+		enum telnet_event_type_t _type; /*!< alias for type */
+		unsigned char state;            /*!< 1 if compression is enabled,
+	                                         0 if disabled */
+	} compress;
+
+	/*! 
+	 * ENVIRON/NEW-ENVIRON event
+	 */
+	struct environ_t {
+		enum telnet_event_type_t _type;        /*!< alias for type */
+		const struct telnet_environ_t *values; /*!< array of variable values */
+		size_t size;                           /*!< number of elements in values */
+		unsigned char cmd;                     /*!< SEND, IS, or INFO */
+	} environ;
+	
+	/*!
+	 * MSSP event
+	 */
+	struct mssp_t {
+		enum telnet_event_type_t _type;        /*!< alias for type */
+		const struct telnet_environ_t *values; /*!< array of variable values */
+		size_t size;                           /*!< number of elements in values */
+	} mssp;
+};
+
+/*! 
+ * \brief event handler
+ *
+ * This is the type of function that must be passed to
+ * telnet_init() when creating a new telnet object.  The
+ * function will be invoked once for every event generated
+ * by the libtelnet protocol parser.
+ *
+ * \param telnet    The telnet object that generated the event
+ * \param event     Event structure with details about the event
+ * \param user_data User-supplied pointer
+ */
+typedef void (*telnet_event_handler_t)(telnet_t *telnet,
+		telnet_event_t *event, void *user_data);
+
+/*! 
+ * telopt support table element; use telopt of -1 for end marker 
+ */
+struct telnet_telopt_t {
+	short telopt;      /*!< one of the TELOPT codes or -1 */
+	unsigned char us;  /*!< TELNET_WILL or TELNET_WONT */
+	unsigned char him; /*!< TELNET_DO or TELNET_DONT */
+};
+
+/*! 
+ * state tracker -- private data structure 
+ */
+struct telnet_t;
+
+/*!
+ * \brief Initialize a telnet state tracker.
+ *
+ * This function initializes a new state tracker, which is used for all
+ * other libtelnet functions.  Each connection must have its own
+ * telnet state tracker object.
+ *
+ * \param telopts   Table of TELNET options the application supports.
+ * \param eh        Event handler function called for every event.
+ * \param flags     0 or TELNET_FLAG_PROXY.
+ * \param user_data Optional data pointer that will be passsed to eh.
+ * \return Telent state tracker object.
+ */
+extern telnet_t* telnet_init(const telnet_telopt_t *telopts,
+		telnet_event_handler_t eh, unsigned char flags, void *user_data);
+
+/*!
+ * \brief Free up any memory allocated by a state tracker.
+ *
+ * This function must be called when a telnet state tracker is no
+ * longer needed (such as after the connection has been closed) to
+ * release any memory resources used by the state tracker.
+ *
+ * \param telnet Telnet state tracker object.
+ */
+extern void telnet_free(telnet_t *telnet);
+
+/*!
+ * \brief Push a byte buffer into the state tracker.
+ *
+ * Passes one or more bytes to the telnet state tracker for
+ * protocol parsing.  The byte buffer is most often going to be
+ * the buffer that recv() was called for while handling the
+ * connection.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param buffer Pointer to byte buffer.
+ * \param size   Number of bytes pointed to by buffer.
+ */
+extern void telnet_recv(telnet_t *telnet, const char *buffer,
+		size_t size);
+
+/*!
+ * \brief Send a telnet command.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param cmd    Command to send.
+ */
+extern void telnet_iac(telnet_t *telnet, unsigned char cmd);
+
+/*!
+ * \brief Send negotiation command.
+ *
+ * Internally, libtelnet uses RFC1143 option negotiation rules.
+ * The negotiation commands sent with this function may be ignored
+ * if they are determined to be redundant.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param cmd    TELNET_WILL, TELNET_WONT, TELNET_DO, or TELNET_DONT.
+ * \param opt    One of the TELNET_TELOPT_* values.
+ */
+extern void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
+		unsigned char opt);
+
+/*!
+ * Send non-command data (escapes IAC bytes).
+ *
+ * \param telnet Telnet state tracker object.
+ * \param buffer Buffer of bytes to send.
+ * \param size   Number of bytes to send.
+ */
+extern void telnet_send(telnet_t *telnet,
+		const char *buffer, size_t size);
+
+/*!
+ * \brief Begin a sub-negotiation command.
+ *
+ * Sends IAC SB followed by the telopt code.  All following data sent
+ * will be part of the sub-negotiation, until telnet_finish_sb() is
+ * called.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param telopt One of the TELNET_TELOPT_* values.
+ */
+extern void telnet_begin_sb(telnet_t *telnet,
+		unsigned char telopt);
+
+/*!
+ * \brief Finish a sub-negotiation command.
+ *
+ * This must be called after a call to telnet_begin_sb() to finish a
+ * sub-negotiation command.
+ *
+ * \param telnet Telnet state tracker object.
+ */
+#define telnet_finish_sb(telnet) telnet_iac((telnet), TELNET_SE)
+
+/*!
+ * \brief Shortcut for sending a complete subnegotiation buffer.
+ *
+ * Equivalent to:
+ *   telnet_begin_sb(telnet, telopt);
+ *   telnet_send(telnet, buffer, size);
+ *   telnet_finish_sb(telnet);
+ *
+ * \param telnet Telnet state tracker format.
+ * \param telopt One of the TELNET_TELOPT_* values.
+ * \param buffer Byte buffer for sub-negotiation data.
+ * \param size   Number of bytes to use for sub-negotiation data.
+ */
+extern void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt,
+		const char *buffer, size_t size);
+
+/*!
+ * \brief Begin sending compressed data.
+ *
+ * This function will begein sending data using the COMPRESS2 option,
+ * which enables the use of zlib to compress data sent to the client.
+ * The client must offer support for COMPRESS2 with option negotiation,
+ * and zlib support must be compiled into libtelnet.
+ *
+ * Only the server may call this command.
+ *
+ * \param telnet Telnet state tracker object.
+ */
+extern void telnet_begin_compress2(telnet_t *telnet);
+
+/*!
+ * \brief Send formatted data.
+ *
+ * This function is a wrapper around telnet_send().  It allows using
+ * printf-style formatting.
+ *
+ * Additionally, this function will translate \\r to the CR NUL construct and
+ * \\n with CR LF, as well as automatically escaping IAC bytes like
+ * telnet_send().
+ *
+ * \param telnet Telnet state tracker object.
+ * \param fmt    Format string.
+ * \return Number of bytes sent.
+ */
+extern int telnet_printf(telnet_t *telnet, const char *fmt, ...)
+		TELNET_GNU_PRINTF(2, 3);
+
+/*!
+ * \brief Send formatted data.
+ *
+ * See telnet_printf().
+ */
+extern int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va);
+
+/*!
+ * \brief Send formatted data (no newline escaping).
+ *
+ * This behaves identically to telnet_printf(), except that the \\r and \\n
+ * characters are not translated.  The IAC byte is still escaped as normal
+ * with telnet_send().
+ *
+ * \param telnet Telnet state tracker object.
+ * \param fmt    Format string.
+ * \return Number of bytes sent.
+ */
+extern int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...)
+		TELNET_GNU_PRINTF(2, 3);
+
+/*!
+ * \brief Send formatted data (no newline escaping).
+ *
+ * See telnet_raw_printf().
+ */
+extern int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va);
+
+/*!
+ * \brief Begin a new set of NEW-ENVIRON values to request or send.
+ *
+ * This function will begin the sub-negotiation block for sending or
+ * requesting NEW-ENVIRON values.
+ *
+ * The telnet_finish_newenviron() macro must be called after this
+ * function to terminate the NEW-ENVIRON command.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param type   One of TELNET_ENVIRON_SEND, TELNET_ENVIRON_IS, or
+ *               TELNET_ENVIRON_INFO.
+ */
+extern void telnet_begin_newenviron(telnet_t *telnet, unsigned char type);
+
+/*!
+ * \brief Send a NEW-ENVIRON variable name or value.
+ *
+ * This can only be called between calls to telnet_begin_newenviron() and
+ * telnet_finish_newenviron().
+ *
+ * \param telnet Telnet state tracker object.
+ * \param type   One of TELNET_ENVIRON_VAR, TELNET_ENVIRON_USERVAR, or
+ *               TELNET_ENVIRON_VALUE.
+ * \param string Variable name or value.
+ */
+extern void telnet_newenviron_value(telnet_t* telnet, unsigned char type,
+		const char *string);
+
+/*!
+ * \brief Finish a NEW-ENVIRON command.
+ *
+ * This must be called after a call to telnet_begin_newenviron() to finish a
+ * NEW-ENVIRON variable list.
+ *
+ * \param telnet Telnet state tracker object.
+ */
+#define telnet_finish_newenviron(telnet) telnet_finish_sb((telnet))
+
+/*!
+ * \brief Send the TERMINAL-TYPE SEND command.
+ *
+ * Sends the sequence IAC TERMINAL-TYPE SEND.
+ *
+ * \param telnet Telnet state tracker object.
+ */
+extern void telnet_ttype_send(telnet_t *telnet);
+
+/*!
+ * \brief Send the TERMINAL-TYPE IS command.
+ *
+ * Sends the sequence IAC TERMINAL-TYPE IS "string".
+ *
+ * According to the RFC, the recipient of a TERMINAL-TYPE SEND shall
+ * send the next possible terminal-type the client supports.  Upon sending
+ * the type, the client should switch modes to begin acting as the terminal
+ * type is just sent.
+ *
+ * The server may continue sending TERMINAL-TYPE IS until it receives a
+ * terminal type is understands.  To indicate to the server that it has
+ * reached the end of the available optoins, the client must send the last
+ * terminal type a second time.  When the server receives the same terminal
+ * type twice in a row, it knows it has seen all available terminal types.
+ *
+ * After the last terminal type is sent, if the client receives another
+ * TERMINAL-TYPE SEND command, it must begin enumerating the available
+ * terminal types from the very beginning.  This allows the server to
+ * scan the available types for a preferred terminal type and, if none
+ * is found, to then ask the client to switch to an acceptable
+ * alternative.
+ *
+ * Note that if the client only supports a single terminal type, then
+ * simply sending that one type in response to every SEND will satisfy
+ * the behavior requirements.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param ttype  Name of the terminal-type being sent.
+ */
+extern void telnet_ttype_is(telnet_t *telnet, const char* ttype);
+
+/*!
+ * \brief Send a ZMP command.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param argc   Number of ZMP commands being sent.
+ * \param argv   Array of argument strings.
+ */
+extern void telnet_send_zmp(telnet_t *telnet, size_t argc, const char **argv);
+
+/*!
+ * \brief Send a ZMP command.
+ *
+ * Arguments are listed out in var-args style.  After the last argument, a
+ * NULL pointer must be passed in as a sentinel value.
+ *
+ * \param telnet Telnet state tracker object.
+ */
+extern void telnet_send_zmpv(telnet_t *telnet, ...);
+
+/*!
+ * \brief Send a ZMP command.
+ *
+ * See telnet_send_zmpv().
+ */
+extern void telnet_send_vzmpv(telnet_t *telnet, va_list va);
+
+/*!
+ * \brief Begin sending a ZMP command
+ *
+ * \param telnet Telnet state tracker object.
+ * \param cmd    The first argument (command name) for the ZMP command.
+ */
+extern void telnet_begin_zmp(telnet_t *telnet, const char *cmd);
+
+/*!
+ * \brief Send a ZMP command argument.
+ *
+ * \param telnet Telnet state tracker object.
+ * \param arg    Telnet argument string.
+ */
+extern void telnet_zmp_arg(telnet_t *telnet, const char *arg);
+
+/*!
+ * \brief Finish a ZMP command.
+ *
+ * This must be called after a call to telnet_begin_zmp() to finish a
+ * ZMP argument list.
+ *
+ * \param telnet Telnet state tracker object.
+ */
+#define telnet_finish_zmp(telnet) telnet_finish_sb((telnet))
+
+/* C++ support */
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+#endif /* !defined(LIBTELNET_INCLUDE) */

Some files were not shown because too many files changed in this diff