├── HolePunching.v11.suo
├── TcpHolePunching
├── TcpHolePunching.suo
├── Peer
│ ├── bin
│ │ └── Debug
│ │ │ ├── Peer.exe
│ │ │ ├── Peer.pdb
│ │ │ ├── Peer.vshost.exe
│ │ │ ├── TcpHolePunching.dll
│ │ │ ├── TcpHolePunching.pdb
│ │ │ └── Peer.vshost.exe.manifest
│ ├── obj
│ │ └── x86
│ │ │ └── Debug
│ │ │ ├── Peer.exe
│ │ │ ├── Peer.pdb
│ │ │ ├── Peer.csprojResolveAssemblyReference.cache
│ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache
│ │ │ └── Peer.csproj.FileListAbsolute.txt
│ ├── NLog.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Peer.csproj
│ └── Program.cs
├── TcpHolePunching.v11.suo
├── IdealPeer
│ ├── bin
│ │ └── Debug
│ │ │ ├── IdealPeer.exe
│ │ │ ├── IdealPeer.pdb
│ │ │ ├── IdealClient.exe
│ │ │ ├── IdealClient.pdb
│ │ │ ├── TcpHolePunching.dll
│ │ │ ├── TcpHolePunching.pdb
│ │ │ ├── IdealPeer.vshost.exe
│ │ │ └── IdealPeer.vshost.exe.manifest
│ ├── obj
│ │ └── Debug
│ │ │ ├── IdealPeer.exe
│ │ │ ├── IdealPeer.pdb
│ │ │ ├── IdealClient.exe
│ │ │ ├── IdealClient.pdb
│ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache
│ │ │ ├── IdealPeer.csprojResolveAssemblyReference.cache
│ │ │ ├── IdealClient.csprojResolveAssemblyReference.cache
│ │ │ ├── IdealPeer.csproj.FileListAbsolute.txt
│ │ │ └── IdealClient.csproj.FileListAbsolute.txt
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Program.cs
│ └── IdealClient.csproj
├── TcpHolePunching
│ ├── bin
│ │ └── Debug
│ │ │ ├── NLog.dll
│ │ │ ├── TcpHolePunching.dll
│ │ │ ├── TcpHolePunching.pdb
│ │ │ ├── TcpHolePunching.vshost.exe
│ │ │ └── TcpHolePunching.vshost.exe.manifest
│ ├── obj
│ │ └── x86
│ │ │ └── Debug
│ │ │ ├── TcpHolePunching.dll
│ │ │ ├── TcpHolePunching.pdb
│ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache
│ │ │ ├── TcpHolePunching.csprojResolveAssemblyReference.cache
│ │ │ └── TcpHolePunching.csproj.FileListAbsolute.txt
│ ├── packages.config
│ ├── Messages
│ │ ├── Message.cs
│ │ ├── ResponseIntroducerRegistrationMessage.cs
│ │ ├── RequestIntroducerRegistrationMessage.cs
│ │ ├── RequestIntroducerIntroductionMessage.cs
│ │ ├── MessageBase.cs
│ │ └── ResponseIntroducerIntroductionMessage.cs
│ ├── MessageSentEventArgs.cs
│ ├── ConnectionAcceptedEventArgs.cs
│ ├── Registrant.cs
│ ├── NLog.config
│ ├── MessageReceivedEventArgs.cs
│ ├── MessageExtensions.cs
│ ├── Client.cs
│ ├── ISerializable.cs
│ ├── NetworkPeer.cs
│ ├── StringExtensions.cs
│ ├── TcpHolePunching.csproj
│ ├── IValueReader.cs
│ ├── StreamValueReader.cs
│ ├── ISerializer.cs
│ ├── StreamValueWriter.cs
│ ├── IValueWriter.cs
│ ├── BufferValueReader.cs
│ ├── NetworkClient.cs
│ ├── NetworkIntroducer.cs
│ ├── SerializerExtensions.cs
│ ├── ObjectSerializer.cs
│ └── BufferValueWriter.cs
├── IdealServer
│ ├── bin
│ │ └── Debug
│ │ │ ├── IdealServer.exe
│ │ │ ├── IdealServer.pdb
│ │ │ ├── TcpHolePunching.dll
│ │ │ └── TcpHolePunching.pdb
│ ├── obj
│ │ └── Debug
│ │ │ ├── IdealServer.exe
│ │ │ ├── IdealServer.pdb
│ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache
│ │ │ ├── IdealServer.csprojResolveAssemblyReference.cache
│ │ │ └── IdealServer.csproj.FileListAbsolute.txt
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Program.cs
│ └── IdealServer.csproj
├── Introducer
│ ├── bin
│ │ └── Debug
│ │ │ ├── Introducer.exe
│ │ │ ├── Introducer.pdb
│ │ │ ├── Introducer.vshost.exe
│ │ │ ├── TcpHolePunching.dll
│ │ │ ├── TcpHolePunching.pdb
│ │ │ └── Introducer.vshost.exe.manifest
│ ├── obj
│ │ └── x86
│ │ │ └── Debug
│ │ │ ├── Introducer.exe
│ │ │ ├── Introducer.pdb
│ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache
│ │ │ ├── Introducer.csprojResolveAssemblyReference.cache
│ │ │ └── Introducer.csproj.FileListAbsolute.txt
│ ├── NLog.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Introducer.csproj
│ └── Program.cs
├── packages
│ ├── NLog.2.0.0.2000
│ │ ├── lib
│ │ │ ├── sl2
│ │ │ │ └── NLog.dll
│ │ │ ├── sl3
│ │ │ │ └── NLog.dll
│ │ │ ├── sl4
│ │ │ │ └── NLog.dll
│ │ │ ├── net20
│ │ │ │ └── NLog.dll
│ │ │ ├── net35
│ │ │ │ └── NLog.dll
│ │ │ ├── net40
│ │ │ │ └── NLog.dll
│ │ │ ├── sl3-wp
│ │ │ │ └── NLog.dll
│ │ │ └── sl4-windowsphone71
│ │ │ │ └── NLog.dll
│ │ └── NLog.2.0.0.2000.nupkg
│ └── repositories.config
├── TcpHolePunching.sln.DotSettings.user
├── TcpHolePunching.sln
└── TcpHolePunching.6.0.ReSharper.user
└── README.md
/HolePunching.v11.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/HolePunching.v11.suo
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching.suo
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/bin/Debug/Peer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/bin/Debug/Peer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/bin/Debug/Peer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/bin/Debug/Peer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching.v11.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching.v11.suo
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/obj/x86/Debug/Peer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/obj/x86/Debug/Peer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/obj/x86/Debug/Peer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/obj/x86/Debug/Peer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/bin/Debug/Peer.vshost.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/bin/Debug/Peer.vshost.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/IdealPeer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/bin/Debug/IdealPeer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/IdealPeer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/bin/Debug/IdealPeer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealPeer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/obj/Debug/IdealPeer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealPeer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/obj/Debug/IdealPeer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/bin/Debug/TcpHolePunching.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/bin/Debug/TcpHolePunching.dll
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/bin/Debug/TcpHolePunching.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/bin/Debug/TcpHolePunching.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/bin/Debug/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/bin/Debug/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/IdealClient.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/bin/Debug/IdealClient.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/IdealClient.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/bin/Debug/IdealClient.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealClient.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/obj/Debug/IdealClient.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealClient.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/obj/Debug/IdealClient.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/bin/Debug/IdealServer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/bin/Debug/IdealServer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/bin/Debug/IdealServer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/bin/Debug/IdealServer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/obj/Debug/IdealServer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/obj/Debug/IdealServer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/obj/Debug/IdealServer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/obj/Debug/IdealServer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/bin/Debug/Introducer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/bin/Debug/Introducer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/bin/Debug/Introducer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/bin/Debug/Introducer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/TcpHolePunching.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/bin/Debug/TcpHolePunching.dll
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/TcpHolePunching.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/bin/Debug/TcpHolePunching.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/obj/x86/Debug/Introducer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/obj/x86/Debug/Introducer.exe
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/obj/x86/Debug/Introducer.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/obj/x86/Debug/Introducer.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/IdealPeer.vshost.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/bin/Debug/IdealPeer.vshost.exe
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/bin/Debug/TcpHolePunching.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/bin/Debug/TcpHolePunching.dll
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/bin/Debug/TcpHolePunching.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/bin/Debug/TcpHolePunching.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/bin/Debug/Introducer.vshost.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/bin/Debug/Introducer.vshost.exe
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/bin/Debug/TcpHolePunching.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/bin/Debug/TcpHolePunching.dll
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/bin/Debug/TcpHolePunching.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/bin/Debug/TcpHolePunching.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl2/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl2/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl3/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl3/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl4/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl4/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/net20/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/net20/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/net35/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/net35/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/net40/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/net40/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl3-wp/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl3-wp/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/bin/Debug/TcpHolePunching.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/bin/Debug/TcpHolePunching.dll
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/bin/Debug/TcpHolePunching.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/bin/Debug/TcpHolePunching.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/NLog.2.0.0.2000.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/NLog.2.0.0.2000.nupkg
--------------------------------------------------------------------------------
/TcpHolePunching/packages/repositories.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/obj/x86/Debug/TcpHolePunching.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/obj/x86/Debug/TcpHolePunching.dll
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/obj/x86/Debug/TcpHolePunching.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/obj/x86/Debug/TcpHolePunching.pdb
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/bin/Debug/TcpHolePunching.vshost.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/bin/Debug/TcpHolePunching.vshost.exe
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl4-windowsphone71/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/packages/NLog.2.0.0.2000/lib/sl4-windowsphone71/NLog.dll
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/obj/x86/Debug/Peer.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/obj/x86/Debug/Peer.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealPeer.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/obj/Debug/IdealPeer.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Peer/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealClient.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealPeer/obj/Debug/IdealClient.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/obj/Debug/IdealServer.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/IdealServer/obj/Debug/IdealServer.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/obj/x86/Debug/Introducer.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/Introducer/obj/x86/Debug/Introducer.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/obj/x86/Debug/TcpHolePunching.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonpang/tcp-holepunching/HEAD/TcpHolePunching/TcpHolePunching/obj/x86/Debug/TcpHolePunching.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Messages/Message.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace TcpHolePunching.Messages
7 | {
8 | public class Message : MessageBase
9 | {
10 | public Message()
11 | : base(MessageType.Internal)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/MessageSentEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace TcpHolePunching
8 | {
9 | public class MessageSentEventArgs : EventArgs
10 | {
11 | public EndPoint To { get; set; }
12 | public int Length { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/ConnectionAcceptedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 |
8 | namespace TcpHolePunching
9 | {
10 | public class ConnectionAcceptedEventArgs : EventArgs
11 | {
12 | public Socket Socket { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Registrant.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace TcpHolePunching
8 | {
9 | public class Registrant
10 | {
11 | public IPEndPoint InternalEndPoint { get; set; }
12 | public IPEndPoint ExternalEndPoint { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/NLog.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/NLog.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/NLog.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/MessageReceivedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using TcpHolePunching.Messages;
7 |
8 | namespace TcpHolePunching
9 | {
10 | public class MessageReceivedEventArgs : EventArgs
11 | {
12 | public IPEndPoint From { get; set; }
13 | public MessageType MessageType { get; set; }
14 | public IValueReader MessageReader { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/bin/Debug/Peer.vshost.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/bin/Debug/IdealPeer.vshost.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/bin/Debug/Introducer.vshost.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/bin/Debug/TcpHolePunching.vshost.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching.sln.DotSettings.user:
--------------------------------------------------------------------------------
1 |
2 | False
3 | Never
4 | True
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/obj/x86/Debug/Peer.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Peer\bin\Debug\Peer.exe
2 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Peer\bin\Debug\Peer.pdb
3 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Peer\bin\Debug\TcpHolePunching.dll
4 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Peer\bin\Debug\TcpHolePunching.pdb
5 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Peer\obj\x86\Debug\Peer.exe
6 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Peer\obj\x86\Debug\Peer.pdb
7 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Peer\obj\x86\Debug\Peer.csprojResolveAssemblyReference.cache
8 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/MessageExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using TcpHolePunching.Messages;
6 |
7 | namespace TcpHolePunching
8 | {
9 | public static class MessageExtensions
10 | {
11 | public static byte[] GetBytes (this MessageBase messageBase)
12 | {
13 | var writer = new BufferValueWriter(new byte[1024]);
14 | messageBase.WritePayload(writer);
15 |
16 | var resizedBuffer = new byte[writer.Length];
17 | Buffer.BlockCopy(writer.Buffer, 0, resizedBuffer, 0, resizedBuffer.Length);
18 |
19 | return resizedBuffer;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealPeer.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\IdealPeer.exe
2 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\IdealPeer.pdb
3 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\TcpHolePunching.dll
4 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\TcpHolePunching.pdb
5 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\obj\Debug\IdealPeer.csprojResolveAssemblyReference.cache
6 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\obj\Debug\IdealPeer.exe
7 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\obj\Debug\IdealPeer.pdb
8 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/obj/Debug/IdealClient.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\IdealClient.exe
2 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\IdealClient.pdb
3 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\TcpHolePunching.dll
4 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\bin\Debug\TcpHolePunching.pdb
5 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\obj\Debug\IdealClient.csprojResolveAssemblyReference.cache
6 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\obj\Debug\IdealClient.exe
7 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealPeer\obj\Debug\IdealClient.pdb
8 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/obj/Debug/IdealServer.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealServer\bin\Debug\IdealServer.exe
2 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealServer\bin\Debug\IdealServer.pdb
3 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealServer\bin\Debug\TcpHolePunching.dll
4 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealServer\bin\Debug\TcpHolePunching.pdb
5 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealServer\obj\Debug\IdealServer.csprojResolveAssemblyReference.cache
6 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealServer\obj\Debug\IdealServer.exe
7 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\IdealServer\obj\Debug\IdealServer.pdb
8 |
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/obj/x86/Debug/Introducer.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Introducer\bin\Debug\Introducer.exe
2 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Introducer\bin\Debug\Introducer.pdb
3 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Introducer\obj\x86\Debug\Introducer.exe
4 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Introducer\obj\x86\Debug\Introducer.pdb
5 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Introducer\bin\Debug\TcpHolePunching.dll
6 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Introducer\bin\Debug\TcpHolePunching.pdb
7 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\Introducer\obj\x86\Debug\Introducer.csprojResolveAssemblyReference.cache
8 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/obj/x86/Debug/TcpHolePunching.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\TcpHolePunching\bin\Debug\TcpHolePunching.dll
2 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\TcpHolePunching\bin\Debug\TcpHolePunching.pdb
3 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\TcpHolePunching\bin\Debug\NLog.dll
4 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\TcpHolePunching\bin\Debug\NLog.xml
5 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\TcpHolePunching\obj\x86\Debug\TcpHolePunching.dll
6 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\TcpHolePunching\obj\x86\Debug\TcpHolePunching.pdb
7 | C:\Users\Jason\Dropbox\TcpHolePunching\TcpHolePunching\TcpHolePunching\obj\x86\Debug\TcpHolePunching.csprojResolveAssemblyReference.cache
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | TCP Hole-Punching
2 | ================
3 |
4 | Purpose
5 | -----------
6 |
7 | To demonstrate hole punching / NAT traversal using the TCP protocol.
8 |
9 | UDP hole punching is more well known and TCP hole punching is less supported by different router models, so this is a proof of concept.
10 |
11 | Instructions
12 | ------------
13 |
14 | 1. Run the Introducer executable on a publicy reachable server (e.g. an Amazon EC2 instance).
15 |
16 | 2. Run the Peer executable on both PCs you want to connect.
17 |
18 | 3. Use a service like cmyip.com to determine the public WAN IPs of each PC, and enter them in each Peer. Hit .
19 |
20 | If the connection succeeds, then TCP hole punching just succeeded.
21 |
22 | * It helps to lower the firewalls on each PC.
23 | * This will most likely not work if either PC is in a corporate network.
24 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 |
8 | namespace TcpHolePunching
9 | {
10 | public class Client
11 | {
12 | ///
13 | /// The socket that belongs to the client.
14 | ///
15 | public Socket Socket { get; set; }
16 |
17 | ///
18 | /// The buffer in which to receive bytes from the transport.
19 | ///
20 | public byte[] Buffer { get; set; }
21 |
22 | public Client(Socket socket)
23 | {
24 | Socket = socket;
25 | Buffer = new byte[1024];
26 | }
27 |
28 | public EndPoint RemoteEndPoint
29 | {
30 | get
31 | {
32 | if (Socket == null)
33 | return null;
34 |
35 | return Socket.RemoteEndPoint;
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Messages/ResponseIntroducerRegistrationMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace TcpHolePunching.Messages
8 | {
9 | public class ResponseIntroducerRegistrationMessage : MessageBase
10 | {
11 | public IPEndPoint RegisteredEndPoint { get; set; }
12 |
13 | public ResponseIntroducerRegistrationMessage()
14 | : base(MessageType.ResponseIntroducerRegistration)
15 | {
16 | }
17 |
18 | public override void WritePayload(IValueWriter writer)
19 | {
20 | base.WritePayload(writer);
21 | writer.WriteBytes(RegisteredEndPoint.Address.GetAddressBytes());
22 | writer.WriteInt32(RegisteredEndPoint.Port);
23 | }
24 |
25 | public override void ReadPayload(IValueReader reader)
26 | {
27 | base.ReadPayload(reader);
28 | var endPointAddress = new IPAddress(reader.ReadBytes());
29 | RegisteredEndPoint = new IPEndPoint(endPointAddress, reader.ReadInt32());
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Messages/RequestIntroducerRegistrationMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace TcpHolePunching.Messages
8 | {
9 | public class RequestIntroducerRegistrationMessage : MessageBase
10 | {
11 | public IPEndPoint InternalClientEndPoint { get; set; }
12 |
13 | public RequestIntroducerRegistrationMessage()
14 | : base(MessageType.RequestIntroducerRegistration)
15 | {
16 | }
17 |
18 | public override void WritePayload(IValueWriter writer)
19 | {
20 | base.WritePayload(writer);
21 | writer.WriteBytes(InternalClientEndPoint.Address.GetAddressBytes());
22 | writer.WriteInt32(InternalClientEndPoint.Port);
23 | }
24 |
25 | public override void ReadPayload(IValueReader reader)
26 | {
27 | base.ReadPayload(reader);
28 | var endPointAddress = new IPAddress(reader.ReadBytes());
29 | InternalClientEndPoint = new IPEndPoint(endPointAddress, reader.ReadInt32());
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Messages/RequestIntroducerIntroductionMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace TcpHolePunching.Messages
8 | {
9 | public class RequestIntroducerIntroductionMessage : MessageBase
10 | {
11 | public IPEndPoint InternalOwnEndPoint { get; set; }
12 | public IPEndPoint ExternalPeerEndPoint { get; set; }
13 |
14 | public RequestIntroducerIntroductionMessage()
15 | : base(MessageType.RequestIntroducerIntroduction)
16 | {
17 | }
18 |
19 | public override void WritePayload(IValueWriter writer)
20 | {
21 | base.WritePayload(writer);
22 | writer.WriteBytes(InternalOwnEndPoint.Address.GetAddressBytes());
23 | writer.WriteInt32(InternalOwnEndPoint.Port);
24 | writer.WriteBytes(ExternalPeerEndPoint.Address.GetAddressBytes());
25 | writer.WriteInt32(ExternalPeerEndPoint.Port);
26 | }
27 |
28 | public override void ReadPayload(IValueReader reader)
29 | {
30 | base.ReadPayload(reader);
31 | var internalEndPointAddress = new IPAddress(reader.ReadBytes());
32 | InternalOwnEndPoint = new IPEndPoint(internalEndPointAddress, reader.ReadInt32());
33 | var externalEndPointAddress = new IPAddress(reader.ReadBytes());
34 | ExternalPeerEndPoint = new IPEndPoint(externalEndPointAddress, reader.ReadInt32());
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("IdealPeer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("IdealPeer")]
13 | [assembly: AssemblyCopyright("Copyright © 2012")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("fcfe1050-9512-4462-a589-357cdda4f1c8")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Peer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("Peer")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2012")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("5c295375-5321-4e7e-b272-a656a01bc56e")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("IdealServer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("IdealServer")]
13 | [assembly: AssemblyCopyright("Copyright © 2012")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b17e6e32-cb0b-4a5a-98d7-279885b815b2")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Introducer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("Introducer")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2012")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f843dc5d-3164-4902-90f2-75559cd3b1d0")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Messages/MessageBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TcpHolePunching.Messages
4 | {
5 | /* Credits to Eric Maupin (Tempest) */
6 | public abstract class MessageBase
7 | {
8 | public MessageType MessageType { get; set; }
9 |
10 | public MessageBase(MessageType messageType)
11 | {
12 | MessageType = messageType;
13 | }
14 |
15 | ///
16 | /// Writes the message payload with .
17 | ///
18 | /// The writer to use for writing the payload.
19 | /// is null.
20 | public virtual void WritePayload(IValueWriter writer)
21 | {
22 | writer.WriteInt32((int) MessageType);
23 | }
24 |
25 | ///
26 | /// Reads the message payload with .
27 | ///
28 | /// The reader to use for reading the payload.
29 | /// is null.
30 | public virtual void ReadPayload(IValueReader reader)
31 | {
32 | MessageType = (MessageType) reader.ReadInt32();
33 | }
34 | }
35 |
36 | public enum MessageType
37 | {
38 | Internal,
39 | RequestIntroducerRegistration,
40 | ResponseIntroducerRegistration,
41 | RequestIntroducerIntroduction,
42 | ResponseIntroducerIntroduction,
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/Messages/ResponseIntroducerIntroductionMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace TcpHolePunching.Messages
8 | {
9 | public class ResponseIntroducerIntroductionMessage : MessageBase
10 | {
11 | ///
12 | /// This is the internal end point of the other peer.
13 | ///
14 | public IPEndPoint InternalPeerEndPoint { get; set; }
15 | ///
16 | /// This is the external end point of the other peer.
17 | ///
18 | public IPEndPoint ExternalPeerEndPoint { get; set; }
19 |
20 | public ResponseIntroducerIntroductionMessage()
21 | : base(MessageType.ResponseIntroducerIntroduction)
22 | {
23 | }
24 |
25 | public override void WritePayload(IValueWriter writer)
26 | {
27 | base.WritePayload(writer);
28 | writer.WriteBytes(InternalPeerEndPoint.Address.GetAddressBytes());
29 | writer.WriteInt32(InternalPeerEndPoint.Port);
30 | writer.WriteBytes(ExternalPeerEndPoint.Address.GetAddressBytes());
31 | writer.WriteInt32(ExternalPeerEndPoint.Port);
32 | }
33 |
34 | public override void ReadPayload(IValueReader reader)
35 | {
36 | base.ReadPayload(reader);
37 | var internalEndPointAddress = new IPAddress(reader.ReadBytes());
38 | InternalPeerEndPoint = new IPEndPoint(internalEndPointAddress, reader.ReadInt32());
39 | var externalEndPointAddress = new IPAddress(reader.ReadBytes());
40 | ExternalPeerEndPoint = new IPEndPoint(externalEndPointAddress, reader.ReadInt32());
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/ISerializable.cs:
--------------------------------------------------------------------------------
1 | //
2 | // ISerializable.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2011 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | namespace TcpHolePunching
28 | {
29 | ///
30 | /// Contract representing a type that can serialize and deserialize itself.
31 | ///
32 | public interface ISerializable
33 | {
34 | ///
35 | /// Serializes the instance to the .
36 | ///
37 | /// The serialization context.
38 | /// The to serialize with.
39 | void Serialize (IValueWriter writer);
40 |
41 | ///
42 | /// Deserializes the instance from the .
43 | ///
44 | /// The serialization context.
45 | /// The to deserialize with.
46 | void Deserialize (IValueReader reader);
47 | }
48 | }
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/NetworkPeer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Sockets;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace TcpHolePunching
11 | {
12 | public class NetworkPeer : NetworkClient
13 | {
14 | public Socket PeerSocket { get; private set; }
15 | public byte[] PeerBuffer { get; private set; }
16 |
17 | public event EventHandler OnConnectionAccepted;
18 |
19 | public NetworkPeer() : base()
20 | {
21 | PeerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
22 | Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
23 | Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
24 | PeerBuffer = new byte[1024];
25 | }
26 |
27 | ///
28 | /// Only binds without listening.
29 | ///
30 | public void Bind(EndPoint on)
31 | {
32 | Socket.Bind(on);
33 | }
34 |
35 | public void Listen()
36 | {
37 | Socket.Listen(Int32.MaxValue);
38 | Task_BeginAccepting();
39 | }
40 |
41 | private void Task_BeginAccepting()
42 | {
43 | var task = Task.Factory.FromAsync(Socket.BeginAccept, Socket.EndAccept, null);
44 | task.ContinueWith(nextTask =>
45 | {
46 | Task_OnConnectionAccepted(task.Result);
47 | Task_BeginAccepting(); // Listen for another connection
48 | }, TaskContinuationOptions.OnlyOnRanToCompletion);
49 | }
50 |
51 | private void Task_OnConnectionAccepted(Socket socket)
52 | {
53 | Console.WriteLine(String.Format("Connection to {0} accepted.", socket.RemoteEndPoint));
54 |
55 | PeerSocket = socket;
56 |
57 | if (OnConnectionAccepted != null)
58 | OnConnectionAccepted(this, new ConnectionAcceptedEventArgs() { Socket = socket} );
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Sockets;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using TcpHolePunching;
11 | using TcpHolePunching.Messages;
12 |
13 | namespace IdealServer
14 | {
15 | public class Program
16 | {
17 | private static NetworkPeer Incoming { get; set; }
18 | private static NetworkPeer Outgoing { get; set; }
19 |
20 | static void Main(string[] args)
21 | {
22 | Console.Title = "Ideal Server - TCP Hole Punching Proof of Concept";
23 |
24 | Incoming = new NetworkPeer();
25 |
26 | Incoming.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
27 | Incoming.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
28 |
29 | Console.Write("Incoming: Bind to which port?: ");
30 | int portToBind = Int32.Parse(Console.ReadLine());
31 | Incoming.Bind(new IPEndPoint(IPAddress.Any, portToBind));
32 | Incoming.Listen();
33 |
34 | Console.WriteLine(String.Format("Listening for clients on {0}...", Incoming.Socket.LocalEndPoint));
35 | Console.ReadLine();
36 |
37 | Outgoing = new NetworkPeer();
38 |
39 | Outgoing.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
40 | Outgoing.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
41 |
42 | Console.Write("Outgoing: Bind to which port?: ");
43 | Outgoing.Bind(new IPEndPoint(IPAddress.Any, portToBind));
44 | Console.Write("Endpoint of your peer: ");
45 |
46 | var introducerEndpoint = Console.ReadLine().Parse();
47 |
48 | Console.WriteLine(String.Format("Connecting to at {0}:{1}...", introducerEndpoint.Address, introducerEndpoint.Port));
49 | Outgoing.Connect(introducerEndpoint.Address, introducerEndpoint.Port);
50 |
51 | Console.ReadLine();
52 |
53 | Application.Run();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Sockets;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using TcpHolePunching;
11 | using TcpHolePunching.Messages;
12 |
13 | namespace IdealClient
14 | {
15 | public class Program
16 | {
17 | private static NetworkPeer Peer { get; set; }
18 |
19 | static void Main(string[] args)
20 | {
21 | Console.Title = "Ideal Client - TCP Hole Punching Proof of Concept";
22 |
23 | Peer = new NetworkPeer();
24 | Peer.OnConnectionAccepted += Peer_OnConnectionAccepted;
25 | Peer.OnConnectionSuccessful += PeerOnConnectionSuccessful;
26 | Peer.OnMessageSent += PeerOnMessageSent;
27 | Peer.OnMessageReceived += Peer_OnMessageReceived;
28 |
29 | Peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
30 | Peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.IpTimeToLive, 1);
31 | Peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
32 |
33 | Console.Write("Bind to which port?: ");
34 | int portToBind = Int32.Parse(Console.ReadLine());
35 | Peer.Bind(new IPEndPoint(IPAddress.Any, portToBind));
36 |
37 | Console.Write("Endpoint of your peer: ");
38 |
39 | var introducerEndpoint = Console.ReadLine().Parse();
40 |
41 | Console.WriteLine(String.Format("Connecting to at {0}:{1}...", introducerEndpoint.Address, introducerEndpoint.Port));
42 | Peer.Connect(introducerEndpoint.Address, introducerEndpoint.Port);
43 |
44 | Console.Write("Press to set socket options back to normal.");
45 | Console.ReadLine();
46 | Peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.IpTimeToLive, 4);
47 |
48 | Application.Run();
49 | }
50 |
51 | static void Peer_OnConnectionAccepted(object sender, ConnectionAcceptedEventArgs e)
52 | {
53 | }
54 |
55 | static void PeerOnConnectionSuccessful(object sender, ConnectionAcceptedEventArgs e)
56 | {
57 | }
58 |
59 | static void PeerOnMessageSent(object sender, MessageSentEventArgs e)
60 | {
61 | }
62 |
63 | static void Peer_OnMessageReceived(object sender, MessageReceivedEventArgs e)
64 | {
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealPeer/IdealClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {CDF17D56-090A-4326-9CC4-57623A56E79A}
8 | Exe
9 | Properties
10 | IdealClient
11 | IdealClient
12 | v4.0
13 | 512
14 |
15 |
16 | x86
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | {a1563fa0-04c7-4818-9d95-fe6383c62f22}
51 | TcpHolePunching
52 |
53 |
54 |
55 |
62 |
--------------------------------------------------------------------------------
/TcpHolePunching/IdealServer/IdealServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}
8 | Exe
9 | Properties
10 | IdealServer
11 | IdealServer
12 | v4.0
13 | 512
14 |
15 |
16 | x86
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | {a1563fa0-04c7-4818-9d95-fe6383c62f22}
51 | TcpHolePunching
52 |
53 |
54 |
55 |
62 |
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/Introducer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 8.0.30703
7 | 2.0
8 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}
9 | Exe
10 | Properties
11 | Introducer
12 | Introducer
13 | v4.0
14 | Client
15 | 512
16 |
17 |
18 | x86
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | x86
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | Designer
52 |
53 |
54 |
55 |
56 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}
57 | TcpHolePunching
58 |
59 |
60 |
61 |
68 |
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/Peer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 8.0.30703
7 | 2.0
8 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}
9 | Exe
10 | Properties
11 | Peer
12 | Peer
13 | v4.0
14 | Client
15 | 512
16 |
17 |
18 | x86
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | x86
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Designer
53 |
54 |
55 |
56 |
57 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}
58 | TcpHolePunching
59 |
60 |
61 |
62 |
69 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 |
7 | namespace TcpHolePunching
8 | {
9 | public static class StringExtensions
10 | {
11 | public static IPEndPoint Parse(this String str, int defaultPort = -1)
12 | {
13 | if (string.IsNullOrEmpty(str)
14 | || str.Trim().Length == 0)
15 | {
16 | throw new ArgumentException("Endpoint descriptor may not be empty.");
17 | }
18 |
19 | if (defaultPort != -1 &&
20 | (defaultPort < IPEndPoint.MinPort
21 | || defaultPort > IPEndPoint.MaxPort))
22 | {
23 | throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultPort));
24 | }
25 |
26 | string[] values = str.Split(new char[] { ':' });
27 | IPAddress ipaddy;
28 | int port = -1;
29 |
30 | //check if we have an IPv6 or ports
31 | if (values.Length <= 2) // ipv4 or hostname
32 | {
33 | if (values.Length == 1)
34 | //no port is specified, default
35 | port = defaultPort;
36 | else
37 | port = AsPort(values[1]);
38 |
39 | //try to use the address as IPv4, otherwise get hostname
40 | if (!IPAddress.TryParse(values[0], out ipaddy))
41 | ipaddy = IpToHost(values[0]);
42 | }
43 | else if (values.Length > 2) //ipv6
44 | {
45 | //could [a:b:c]:d
46 | if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]"))
47 | {
48 | string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
49 | ipaddy = IPAddress.Parse(ipaddressstring);
50 | port = AsPort(values[values.Length - 1]);
51 | }
52 | else //[a:b:c] or a:b:c
53 | {
54 | ipaddy = IPAddress.Parse(str);
55 | port = defaultPort;
56 | }
57 | }
58 | else
59 | {
60 | throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", str));
61 | }
62 |
63 | if (port == -1)
64 | throw new ArgumentException(string.Format("No port specified: '{0}'", str));
65 |
66 | return new IPEndPoint(ipaddy, port);
67 | }
68 |
69 | private static int AsPort(this String str)
70 | {
71 | int port;
72 |
73 | if (!int.TryParse(str, out port)
74 | || port < IPEndPoint.MinPort
75 | || port > IPEndPoint.MaxPort)
76 | {
77 | throw new FormatException(string.Format("Invalid end point port '{0}'", str));
78 | }
79 |
80 | return port;
81 | }
82 |
83 | private static IPAddress IpToHost(this String str)
84 | {
85 | var hosts = Dns.GetHostAddresses(str);
86 |
87 | if (hosts == null || hosts.Length == 0)
88 | throw new ArgumentException(string.Format("Host not found: {0}", str));
89 |
90 | return hosts[0];
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/TcpHolePunching.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 8.0.30703
7 | 2.0
8 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}
9 | Library
10 | Properties
11 | TcpHolePunching
12 | TcpHolePunching
13 | v4.0
14 | Client
15 | 512
16 |
17 |
18 | x86
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 | true
27 |
28 |
29 | x86
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 | ..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll
43 |
44 |
45 |
46 |
47 |
48 | Designer
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
88 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/IValueReader.cs:
--------------------------------------------------------------------------------
1 | //
2 | // IValueReader.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2010 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | using System;
28 | using System.Linq;
29 | using System.Text;
30 | using TcpHolePunching.Messages;
31 |
32 | namespace TcpHolePunching
33 | {
34 | public interface IValueReader
35 | {
36 | ///
37 | /// Reads a boolean from the transport.
38 | ///
39 | bool ReadBool();
40 |
41 | ///
42 | /// Reads an array of unsigned bytes from the transport.
43 | ///
44 | byte[] ReadBytes ();
45 |
46 | ///
47 | /// Reads the next bytes from the transport.
48 | ///
49 | /// The number of bytes to read.
50 | /// is < 0.
51 | byte[] ReadBytes (int count);
52 |
53 | ///
54 | /// Reads a signed byte (SByte) from the transport.
55 | ///
56 | SByte ReadSByte ();
57 |
58 | ///
59 | /// Reads a signed short (Int16) from the transport.
60 | ///
61 | Int16 ReadInt16 ();
62 |
63 | ///
64 | /// Reads a signed integer (Int32) from the transport.
65 | ///
66 | Int32 ReadInt32 ();
67 |
68 | ///
69 | /// Reads a signed long (Int64) from the transport.
70 | ///
71 | Int64 ReadInt64 ();
72 |
73 | ///
74 | /// Reads an unsigned byte (Byte) from the transport.
75 | ///
76 | Byte ReadByte ();
77 |
78 | ///
79 | /// Reads an unsigned integer (UInt16) from the transport.
80 | ///
81 | ///
82 | UInt16 ReadUInt16 ();
83 |
84 | ///
85 | /// Reads an unsigned integer (UInt32) from the transport.
86 | ///
87 | ///
88 | UInt32 ReadUInt32 ();
89 |
90 | ///
91 | /// Reads an unsigned long (UInt64) from the transport.
92 | ///
93 | UInt64 ReadUInt64 ();
94 |
95 | ///
96 | /// Reads a decimal from the transport.
97 | ///
98 | Decimal ReadDecimal ();
99 |
100 | ///
101 | /// Reads a single from the transport.
102 | ///
103 | Single ReadSingle();
104 |
105 | ///
106 | /// Reads a double from the transport.
107 | ///
108 | Double ReadDouble();
109 |
110 | ///
111 | /// Reads a string with from the transport.
112 | ///
113 | /// The encoding of the string.
114 | /// is null.
115 | string ReadString (Encoding encoding);
116 |
117 | ///
118 | /// Finalizes buffer.
119 | ///
120 | /// Connection providers should call this automatically when returns.
121 | void Flush();
122 | }
123 | }
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/StreamValueReader.cs:
--------------------------------------------------------------------------------
1 | //
2 | // StreamValueReader.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2010 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | using System;
28 | using System.IO;
29 | using System.Linq;
30 | using System.Text;
31 |
32 | namespace TcpHolePunching
33 | {
34 | public class StreamValueReader
35 | : IValueReader
36 | {
37 | private readonly Stream stream;
38 |
39 | public StreamValueReader (Stream stream)
40 | {
41 | if (stream == null)
42 | throw new ArgumentNullException ("stream");
43 | if (!stream.CanRead)
44 | throw new ArgumentException ("Can not read from this stream", "stream");
45 |
46 | this.stream = stream;
47 | }
48 |
49 | public bool ReadBool()
50 | {
51 | return (ReadByte() == 1);
52 | }
53 |
54 | public byte[] ReadBytes()
55 | {
56 | int count = ReadInt32();
57 | return ReadBytes (count);
58 | }
59 |
60 | public byte[] ReadBytes (int count)
61 | {
62 | if (count < 0)
63 | throw new ArgumentOutOfRangeException ("count", "count must be >= 0");
64 |
65 | byte[] buffer = new byte[count];
66 |
67 | int i = 0;
68 | int bytes;
69 | while (i < buffer.Length && (bytes = this.stream.Read (buffer, i, count)) > 0)
70 | {
71 | i += bytes;
72 | count -= bytes;
73 | }
74 |
75 | return buffer;
76 | }
77 |
78 | public sbyte ReadSByte()
79 | {
80 | return (sbyte)this.stream.ReadByte();
81 | }
82 |
83 | public short ReadInt16()
84 | {
85 | return BitConverter.ToInt16 (ReadBytes (sizeof (short)), 0);
86 | }
87 |
88 | public int ReadInt32()
89 | {
90 | return BitConverter.ToInt32 (ReadBytes (sizeof (int)), 0);
91 | }
92 |
93 | public long ReadInt64()
94 | {
95 | return BitConverter.ToInt64 (ReadBytes (sizeof (long)), 0);
96 | }
97 |
98 | public byte ReadByte()
99 | {
100 | return (byte)this.stream.ReadByte();
101 | }
102 |
103 | public ushort ReadUInt16()
104 | {
105 | return BitConverter.ToUInt16 (ReadBytes (sizeof (ushort)), 0);
106 | }
107 |
108 | public uint ReadUInt32()
109 | {
110 | return BitConverter.ToUInt32 (ReadBytes (sizeof (uint)), 0);
111 | }
112 |
113 | public ulong ReadUInt64()
114 | {
115 | return BitConverter.ToUInt64 (ReadBytes (sizeof (ulong)), 0);
116 | }
117 |
118 | public string ReadString (Encoding encoding)
119 | {
120 | if (encoding == null)
121 | throw new ArgumentNullException ("encoding");
122 |
123 | byte[] data = ReadBytes();
124 | return (data.Length == 0) ? null : encoding.GetString (data, 0, data.Length);
125 | }
126 |
127 | public decimal ReadDecimal()
128 | {
129 | int len = ReadInt32();
130 | int[] bits = new int[len];
131 | for (int i = 0; i < bits.Length; ++i)
132 | bits[i] = ReadInt32();
133 |
134 | return new decimal (bits);
135 | }
136 |
137 | public float ReadSingle()
138 | {
139 | return BitConverter.ToSingle (ReadBytes (sizeof (float)), 0);
140 | }
141 |
142 | public double ReadDouble()
143 | {
144 | return BitConverter.ToDouble (ReadBytes (sizeof (double)), 0);
145 | }
146 |
147 | public void Flush()
148 | {
149 | this.stream.Flush();
150 | }
151 | }
152 | }
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/ISerializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // ISerializer.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2011 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | using System;
28 |
29 | namespace TcpHolePunching
30 | {
31 | ///
32 | /// Contract for a type that serializes another type.
33 | ///
34 | public interface ISerializer
35 | {
36 | ///
37 | /// Serializes using .
38 | ///
39 | /// The serialization context.
40 | /// The writer to use to serialize.
41 | /// The element to serialize.
42 | void Serialize (IValueWriter writer, object element);
43 |
44 | ///
45 | /// Deserializes an element with .
46 | ///
47 | /// The serialization context.
48 | /// The reader to use to deserialize.
49 | /// The deserialized element.
50 | object Deserialize (IValueReader reader);
51 | }
52 |
53 | ///
54 | /// Contract for a type that serializes another type.
55 | ///
56 | /// The type to serialize and deserialize.
57 | public interface ISerializer
58 | {
59 | ///
60 | /// Serializes using .
61 | ///
62 | /// The serialization context.
63 | /// The writer to use to serialize.
64 | /// The element to serialize.
65 | void Serialize (IValueWriter writer, T element);
66 |
67 | ///
68 | /// Deserializes an element with .
69 | ///
70 | /// The serialization context.
71 | /// The reader to use to deserialize.
72 | /// The deserialized element.
73 | T Deserialize (IValueReader reader);
74 | }
75 |
76 | public static class Serializer
77 | {
78 | public static readonly ISerializer Default = new DefaultSerializer();
79 |
80 | private class DefaultSerializer
81 | : ISerializer
82 | {
83 | public void Serialize (IValueWriter writer, T element)
84 | {
85 | Type etype;
86 | if (element != null)
87 | {
88 | etype = element.GetType();
89 | if (etype.IsValueType && typeof (T) == typeof (object))
90 | etype = typeof (object);
91 | }
92 | else
93 | etype = typeof (object);
94 |
95 | ObjectSerializer.GetSerializer (etype).Serialize (writer, element);
96 | }
97 |
98 | public T Deserialize (IValueReader reader)
99 | {
100 | return (T)ObjectSerializer.GetSerializer (typeof (T)).Deserialize (reader);
101 | }
102 | }
103 | }
104 |
105 | internal class FixedSerializer
106 | : ISerializer
107 | {
108 | public FixedSerializer (Type type)
109 | {
110 | if (type == null)
111 | throw new ArgumentNullException ("type");
112 |
113 | this.serializer = ObjectSerializer.GetSerializer (type);
114 | }
115 |
116 | public void Serialize (IValueWriter writer, object element)
117 | {
118 | this.serializer.Serialize (writer, element);
119 | }
120 |
121 | public object Deserialize (IValueReader reader)
122 | {
123 | return this.serializer.Deserialize (reader);
124 | }
125 |
126 | private readonly ObjectSerializer serializer;
127 | }
128 | }
--------------------------------------------------------------------------------
/TcpHolePunching/Introducer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using TcpHolePunching;
7 | using TcpHolePunching.Messages;
8 |
9 | namespace Introducer
10 | {
11 | class Program
12 | {
13 | private static NetworkIntroducer Introducer { get; set; }
14 |
15 | static void Main(string[] args)
16 | {
17 | Console.Title = "Introducer - TCP Hole Punching Proof of Concept";
18 |
19 | Introducer = new NetworkIntroducer();
20 | Introducer.OnConnectionAccepted += Introducer_OnConnectionAccepted;
21 | Introducer.OnMessageSent += Introducer_OnMessageSent;
22 | Introducer.OnMessageReceived += Introducer_OnMessageReceived;
23 |
24 | Introducer.Listen(new IPEndPoint(IPAddress.Any, 1618));
25 | Console.WriteLine(String.Format("Listening for clients on {0}...", Introducer.Socket.LocalEndPoint));
26 |
27 | Console.ReadLine();
28 | }
29 |
30 | static void Introducer_OnConnectionAccepted(object sender, ConnectionAcceptedEventArgs e)
31 | {
32 | }
33 |
34 | static void Introducer_OnMessageSent(object sender, MessageSentEventArgs e)
35 | {
36 | }
37 |
38 | static void Introducer_OnMessageReceived(object sender, MessageReceivedEventArgs e)
39 | {
40 | switch (e.MessageType)
41 | {
42 | case MessageType.RequestIntroducerRegistration:
43 | {
44 | var message = new RequestIntroducerRegistrationMessage();
45 | message.ReadPayload(e.MessageReader);
46 |
47 | // A client wants to register
48 | // Get his internal endpoint
49 | var internalEndPoint = message.InternalClientEndPoint;
50 | // Get his external endpoint
51 | var externalEndPoint = e.From;
52 |
53 | Introducer.Registrants.Add(new Registrant()
54 | {
55 | InternalEndPoint = internalEndPoint,
56 | ExternalEndPoint = externalEndPoint
57 | });
58 |
59 | Introducer.Send(e.From, new ResponseIntroducerRegistrationMessage()
60 | {
61 | RegisteredEndPoint = e.From
62 | });
63 | }
64 | break;
65 | case MessageType.RequestIntroducerIntroduction:
66 | {
67 | var message = new RequestIntroducerIntroductionMessage();
68 | message.ReadPayload(e.MessageReader);
69 |
70 | // A client, A, wants to be introduced to another peer, B
71 | var bExternalEndPoint = message.ExternalPeerEndPoint;
72 |
73 | // Get this peer's registration
74 | var b =
75 | Introducer.Registrants.First(
76 | registrant => registrant.ExternalEndPoint.Equals(message.ExternalPeerEndPoint));
77 |
78 | var a = new Registrant()
79 | {InternalEndPoint = message.InternalOwnEndPoint, ExternalEndPoint = e.From};
80 |
81 | Introducer.Send(a.ExternalEndPoint, new ResponseIntroducerIntroductionMessage()
82 | {
83 | InternalPeerEndPoint = b.InternalEndPoint,
84 | ExternalPeerEndPoint = b.ExternalEndPoint,
85 | });
86 |
87 | Introducer.Send(b.ExternalEndPoint, new ResponseIntroducerIntroductionMessage()
88 | {
89 | InternalPeerEndPoint = a.InternalEndPoint,
90 | ExternalPeerEndPoint = a.ExternalEndPoint,
91 | });
92 | }
93 | break;
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/StreamValueWriter.cs:
--------------------------------------------------------------------------------
1 | //
2 | // StreamValueWriter.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2011 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | using System;
28 | using System.IO;
29 | using System.Linq;
30 | using System.Text;
31 |
32 | namespace TcpHolePunching
33 | {
34 | public class StreamValueWriter
35 | : IValueWriter
36 | {
37 | private readonly Stream stream;
38 |
39 | public StreamValueWriter (Stream stream)
40 | {
41 | if (stream == null)
42 | throw new ArgumentNullException ("stream");
43 | if (!stream.CanWrite)
44 | throw new ArgumentException ("Can not write to this stream", "stream");
45 | if (!BitConverter.IsLittleEndian) // TODO: Support.
46 | throw new NotSupportedException ("Big Endian architecture not supported");
47 |
48 | this.stream = stream;
49 | }
50 |
51 | public void WriteByte (byte value)
52 | {
53 | this.stream.WriteByte (value);
54 | }
55 |
56 | public void WriteSByte (sbyte value)
57 | {
58 | this.stream.WriteByte ((byte)value);
59 | }
60 |
61 | public bool WriteBool (bool value)
62 | {
63 | this.stream.WriteByte ((byte)((value) ? 1 : 0));
64 |
65 | return value;
66 | }
67 |
68 | public void WriteBytes (byte[] value)
69 | {
70 | if (value == null)
71 | throw new ArgumentNullException ("value");
72 |
73 | WriteInt32 (value.Length);
74 | this.stream.Write (value, 0, value.Length);
75 | }
76 |
77 | public void WriteBytes (byte[] value, int offset, int length)
78 | {
79 | if (value == null)
80 | throw new ArgumentNullException ("value");
81 | if (offset < 0 || offset >= value.Length)
82 | throw new ArgumentOutOfRangeException ("offset", "offset can not negative or >=data.Length");
83 | if (length < 0 || offset + length >= value.Length)
84 | throw new ArgumentOutOfRangeException ("length", "length can not be negative or combined with offset longer than the array");
85 |
86 | WriteInt32 (length);
87 | this.stream.Write (value, offset, length);
88 | }
89 |
90 | public void WriteInt16 (short value)
91 | {
92 | Write (BitConverter.GetBytes (value));
93 | }
94 |
95 | public void WriteInt32 (int value)
96 | {
97 | Write (BitConverter.GetBytes (value));
98 | }
99 |
100 | public void WriteInt64 (long value)
101 | {
102 | Write (BitConverter.GetBytes (value));
103 | }
104 |
105 | public void WriteUInt16 (ushort value)
106 | {
107 | Write (BitConverter.GetBytes (value));
108 | }
109 |
110 | public void WriteUInt32 (uint value)
111 | {
112 | Write (BitConverter.GetBytes (value));
113 | }
114 |
115 | public void WriteUInt64 (ulong value)
116 | {
117 | Write (BitConverter.GetBytes (value));
118 | }
119 |
120 | public void WriteDecimal (decimal value)
121 | {
122 | int[] bits = Decimal.GetBits (value);
123 | WriteInt32 (bits.Length);
124 | for (int i = 0; i < bits.Length; ++i)
125 | WriteInt32 (bits[i]);
126 | }
127 |
128 | public void WriteSingle (float value)
129 | {
130 | Write (BitConverter.GetBytes (value));
131 | }
132 |
133 | public void WriteDouble (double value)
134 | {
135 | Write (BitConverter.GetBytes (value));
136 | }
137 |
138 | public void WriteString (Encoding encoding, string value)
139 | {
140 | if (encoding == null)
141 | throw new ArgumentNullException ("encoding");
142 |
143 | WriteBytes (!String.IsNullOrEmpty (value) ? encoding.GetBytes (value) : new byte[0]);
144 | }
145 |
146 | public void Flush()
147 | {
148 | this.stream.Flush();
149 | }
150 |
151 | private void Write (byte[] data)
152 | {
153 | this.stream.Write (data, 0, data.Length);
154 | }
155 | }
156 | }
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/IValueWriter.cs:
--------------------------------------------------------------------------------
1 | //
2 | // IValueWriter.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2010 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | using System;
28 | using System.Linq;
29 | using System.Text;
30 |
31 | namespace TcpHolePunching
32 | {
33 | ///
34 | /// Serialization contract.
35 | ///
36 | public interface IValueWriter
37 | {
38 | ///
39 | /// Writes an unsigned byte to the transport.
40 | ///
41 | ///
42 | void WriteByte (byte value);
43 |
44 | ///
45 | /// Writes a signed byte to the transport.
46 | ///
47 | /// The value to write.
48 | void WriteSByte (sbyte value);
49 |
50 | ///
51 | /// Writes a boolean to the transport.
52 | ///
53 | /// The value to write.
54 | ///
55 | bool WriteBool (bool value);
56 |
57 | ///
58 | /// Writes an array of unsigned bytes to the transport.
59 | ///
60 | /// The value to write.
61 | /// is null.
62 | void WriteBytes (byte[] value);
63 |
64 | ///
65 | /// Writes an array segment to the transport.
66 | ///
67 | /// The array to write from.
68 | /// The offset of to start writing from.
69 | /// The length to write from in .
70 | ///
71 | void WriteBytes (byte[] value, int offset, int length);
72 |
73 | ///
74 | /// Writes a signed short (Int16) to the transport.
75 | ///
76 | /// The value to write.
77 | void WriteInt16 (Int16 value);
78 |
79 | ///
80 | /// Writes a signed integer (Int32) to the transport.
81 | ///
82 | /// The value to write.
83 | void WriteInt32 (Int32 value);
84 |
85 | ///
86 | /// Writes a signed long (Int64) to the transport.
87 | ///
88 | /// The value to write.
89 | void WriteInt64 (Int64 value);
90 |
91 | ///
92 | /// Writes an unsigned short to the transport.
93 | ///
94 | /// The value to write.
95 | void WriteUInt16 (UInt16 value);
96 |
97 | ///
98 | /// Writes an unsigned integer to the transport.
99 | ///
100 | /// The value to write.
101 | void WriteUInt32 (UInt32 value);
102 |
103 | ///
104 | /// Writes an unsigned long to the transport.
105 | ///
106 | /// The value to write.
107 | void WriteUInt64 (UInt64 value);
108 |
109 | ///
110 | /// Writes a decimal to the transport.
111 | ///
112 | /// The value to write
113 | void WriteDecimal (Decimal value);
114 |
115 | ///
116 | /// Writes a single to the transport.
117 | ///
118 | /// The value to write
119 | void WriteSingle (Single value);
120 |
121 | ///
122 | /// Writes a double to the transport.
123 | ///
124 | /// The value to write
125 | void WriteDouble (Double value);
126 |
127 | ///
128 | /// Writes a string with to the transport.
129 | ///
130 | /// The encoding to use.
131 | /// The value to write.
132 | void WriteString (Encoding encoding, string value);
133 |
134 | ///
135 | /// Flushes any buffered data to the transport.
136 | ///
137 | void Flush();
138 | }
139 | }
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Introducer", "Introducer\Introducer.csproj", "{B0C3DD03-FE40-4123-85D4-81E812A052D0}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Peer", "Peer\Peer.csproj", "{505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpHolePunching", "TcpHolePunching\TcpHolePunching.csproj", "{A1563FA0-04C7-4818-9D95-FE6383C62F22}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdealClient", "IdealPeer\IdealClient.csproj", "{CDF17D56-090A-4326-9CC4-57623A56E79A}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdealServer", "IdealServer\IdealServer.csproj", "{C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Debug|Mixed Platforms = Debug|Mixed Platforms
18 | Debug|x86 = Debug|x86
19 | Release|Any CPU = Release|Any CPU
20 | Release|Mixed Platforms = Release|Mixed Platforms
21 | Release|x86 = Release|x86
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Debug|Any CPU.ActiveCfg = Debug|x86
25 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
26 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Debug|Mixed Platforms.Build.0 = Debug|x86
27 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Debug|x86.ActiveCfg = Debug|x86
28 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Debug|x86.Build.0 = Debug|x86
29 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Release|Any CPU.ActiveCfg = Release|x86
30 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Release|Mixed Platforms.ActiveCfg = Release|x86
31 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Release|Mixed Platforms.Build.0 = Release|x86
32 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Release|x86.ActiveCfg = Release|x86
33 | {B0C3DD03-FE40-4123-85D4-81E812A052D0}.Release|x86.Build.0 = Release|x86
34 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Debug|Any CPU.ActiveCfg = Debug|x86
35 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
36 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Debug|Mixed Platforms.Build.0 = Debug|x86
37 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Debug|x86.ActiveCfg = Debug|x86
38 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Debug|x86.Build.0 = Debug|x86
39 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Release|Any CPU.ActiveCfg = Release|x86
40 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Release|Mixed Platforms.ActiveCfg = Release|x86
41 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Release|Mixed Platforms.Build.0 = Release|x86
42 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Release|x86.ActiveCfg = Release|x86
43 | {505A5ACD-FACD-4B76-9D9D-C40F3EB33DDD}.Release|x86.Build.0 = Release|x86
44 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Debug|Any CPU.ActiveCfg = Debug|x86
45 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
46 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Debug|Mixed Platforms.Build.0 = Debug|x86
47 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Debug|x86.ActiveCfg = Debug|x86
48 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Debug|x86.Build.0 = Debug|x86
49 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Release|Any CPU.ActiveCfg = Release|x86
50 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Release|Mixed Platforms.ActiveCfg = Release|x86
51 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Release|Mixed Platforms.Build.0 = Release|x86
52 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Release|x86.ActiveCfg = Release|x86
53 | {A1563FA0-04C7-4818-9D95-FE6383C62F22}.Release|x86.Build.0 = Release|x86
54 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
57 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
58 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Debug|x86.ActiveCfg = Debug|Any CPU
59 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
62 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
63 | {CDF17D56-090A-4326-9CC4-57623A56E79A}.Release|x86.ActiveCfg = Release|Any CPU
64 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
65 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
66 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
67 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
68 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Debug|x86.ActiveCfg = Debug|Any CPU
69 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
70 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Release|Any CPU.Build.0 = Release|Any CPU
71 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
72 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
73 | {C71EDA02-7098-479E-9B4E-3DD0A2C83FFC}.Release|x86.ActiveCfg = Release|Any CPU
74 | EndGlobalSection
75 | GlobalSection(SolutionProperties) = preSolution
76 | HideSolutionNode = FALSE
77 | EndGlobalSection
78 | EndGlobal
79 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/BufferValueReader.cs:
--------------------------------------------------------------------------------
1 | //
2 | // BufferValueReader.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2011-2012 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | using System;
28 | using System.IO;
29 | using System.Text;
30 | using Buff = System.Buffer;
31 |
32 | namespace TcpHolePunching
33 | {
34 | public class BufferValueReader
35 | : IValueReader
36 | {
37 | private readonly byte[] buffer;
38 | private readonly int length;
39 |
40 | public BufferValueReader (byte[] buffer)
41 | {
42 | if (buffer == null)
43 | throw new ArgumentNullException ("buffer");
44 |
45 | this.buffer = buffer;
46 | this.length = buffer.Length;
47 | }
48 |
49 | public BufferValueReader (byte[] buffer, int offset, int length)
50 | {
51 | if (buffer == null)
52 | throw new ArgumentNullException ("buffer");
53 |
54 | this.buffer = buffer;
55 | this.position = offset;
56 | this.length = length;
57 | }
58 |
59 | ///
60 | /// Gets the underlying buffer.
61 | ///
62 | public byte[] Buffer
63 | {
64 | get { return this.buffer; }
65 | }
66 |
67 | ///
68 | /// Gets or sets the position of the reader in the buffer.
69 | ///
70 | public int Position
71 | {
72 | get { return this.position; }
73 | set { this.position = value; }
74 | }
75 |
76 | public bool ReadBool()
77 | {
78 | return (this.buffer[this.position++] == 1);
79 | }
80 |
81 | public byte[] ReadBytes()
82 | {
83 | int len = ReadInt32();
84 |
85 | byte[] b = new byte[len];
86 | Buff.BlockCopy (this.buffer, this.Position, b, 0, len);
87 | this.Position += len;
88 |
89 | return b;
90 | }
91 |
92 | public byte[] ReadBytes (int count)
93 | {
94 | if (count < 0)
95 | throw new ArgumentOutOfRangeException ("count", "count must be >= 0");
96 |
97 | byte[] b = new byte[count];
98 | Buff.BlockCopy (this.buffer, this.position, b, 0, count);
99 | this.position += count;
100 |
101 | return b;
102 | }
103 |
104 | public sbyte ReadSByte()
105 | {
106 | return (sbyte)this.buffer[this.position++];
107 | }
108 |
109 | public short ReadInt16()
110 | {
111 | short v = BitConverter.ToInt16 (this.buffer, this.position);
112 | this.position += sizeof (short);
113 |
114 | return v;
115 | }
116 |
117 | public int ReadInt32()
118 | {
119 | int v = BitConverter.ToInt32 (this.buffer, this.position);
120 | this.position += sizeof (int);
121 |
122 | return v;
123 | }
124 |
125 | public long ReadInt64()
126 | {
127 | long v = BitConverter.ToInt64 (this.buffer, this.position);
128 | this.position += sizeof (long);
129 |
130 | return v;
131 | }
132 |
133 | public byte ReadByte()
134 | {
135 | return this.buffer[this.position++];
136 | }
137 |
138 | public ushort ReadUInt16()
139 | {
140 | ushort v = BitConverter.ToUInt16 (this.buffer, this.position);
141 | this.position += sizeof (ushort);
142 |
143 | return v;
144 | }
145 |
146 | public uint ReadUInt32()
147 | {
148 | uint v = BitConverter.ToUInt32 (this.buffer, this.position);
149 | this.position += sizeof (uint);
150 |
151 | return v;
152 | }
153 |
154 | public ulong ReadUInt64()
155 | {
156 | ulong v = BitConverter.ToUInt64 (this.buffer, this.position);
157 | this.position += sizeof (ulong);
158 |
159 | return v;
160 | }
161 |
162 | public decimal ReadDecimal()
163 | {
164 | int[] parts = new int[4];
165 | for (int i = 0; i < parts.Length; ++i)
166 | parts[i] = ReadInt32 ();
167 |
168 | return new decimal (parts);
169 | }
170 |
171 | public float ReadSingle()
172 | {
173 | float v = BitConverter.ToSingle (this.buffer, this.position);
174 | this.position += sizeof (float);
175 |
176 | return v;
177 | }
178 |
179 | public double ReadDouble ()
180 | {
181 | double v = BitConverter.ToDouble (this.buffer, this.position);
182 | this.position += sizeof (double);
183 |
184 | return v;
185 | }
186 |
187 | public string ReadString (Encoding encoding)
188 | {
189 | if (encoding == null)
190 | throw new ArgumentNullException ("encoding");
191 |
192 | int len = Read7BitEncodedInt();
193 | if (len == -1)
194 | return null;
195 |
196 | string v = encoding.GetString (this.buffer, this.position, len);
197 | this.Position += len;
198 |
199 | return v;
200 | }
201 |
202 | public void Flush()
203 | {
204 | }
205 |
206 | private int position;
207 |
208 | private int Read7BitEncodedInt()
209 | {
210 | int count = 0;
211 | int shift = 0;
212 | byte b;
213 |
214 | do
215 | {
216 | b = ReadByte();
217 |
218 | count |= (b & 127) << shift;
219 | shift += 7;
220 | } while ((b & 128) != 0);
221 |
222 | return count;
223 | }
224 | }
225 | }
--------------------------------------------------------------------------------
/TcpHolePunching/Peer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Sockets;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using TcpHolePunching;
11 | using TcpHolePunching.Messages;
12 |
13 | namespace Peer
14 | {
15 | public class Program
16 | {
17 | private static NetworkPeer IntroducerSocket { get; set; }
18 | private static NetworkPeer ListenSocket { get; set; }
19 | private static NetworkPeer ConnectSocketInternal { get; set; }
20 | private static NetworkPeer ConnectSocketExternal { get; set; }
21 |
22 | private static int PORT = 53472;
23 |
24 | static void Main(string[] args)
25 | {
26 | Console.Title = "Peer - TCP Hole Punching Proof of Concept";
27 |
28 | ListenSocket = new NetworkPeer();
29 | ListenSocket.OnConnectionAccepted += (s, e1) => Console.WriteLine("ListenSocket.OnConnectionAccepted");
30 | ListenSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
31 | ListenSocket.Listen();
32 | Console.WriteLine(String.Format("Listening for clients on {0}...", ListenSocket.Socket.LocalEndPoint));
33 |
34 | IntroducerSocket = new NetworkPeer();
35 | IntroducerSocket.OnConnectionAccepted += Peer_OnConnectionAccepted;
36 | IntroducerSocket.OnConnectionSuccessful += PeerOnConnectionSuccessful;
37 | IntroducerSocket.OnMessageSent += PeerOnMessageSent;
38 | IntroducerSocket.OnMessageReceived += Peer_OnMessageReceived;
39 |
40 | IntroducerSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
41 |
42 | Console.Write("Endpoint of the introducer (try 50.18.245.235:1618): ");
43 |
44 | var input = Console.ReadLine();
45 | input = (String.IsNullOrEmpty(input)) ? "50.18.245.235:1618" : input;
46 | var introducerEndpoint = input.Parse();
47 |
48 | Console.WriteLine(String.Format("Connecting to the Introducer at {0}:{1}...", introducerEndpoint.Address, introducerEndpoint.Port));
49 | IntroducerSocket.Connect(introducerEndpoint.Address, introducerEndpoint.Port);
50 |
51 | Application.Run();
52 | }
53 |
54 | static void Peer_OnConnectionAccepted(object sender, ConnectionAcceptedEventArgs e)
55 | {
56 | Console.WriteLine();
57 | }
58 |
59 | static void PeerOnConnectionSuccessful(object sender, ConnectionAcceptedEventArgs e)
60 | {
61 | Console.WriteLine();
62 | Console.WriteLine("Requesting to register with the Introducer...");
63 | IntroducerSocket.Send(new RequestIntroducerRegistrationMessage() { InternalClientEndPoint = (IPEndPoint) e.Socket.LocalEndPoint} );
64 | }
65 |
66 | static void PeerOnMessageSent(object sender, MessageSentEventArgs e)
67 | {
68 | }
69 |
70 | static void Peer_OnMessageReceived(object sender, MessageReceivedEventArgs e)
71 | {
72 | switch (e.MessageType)
73 | {
74 | case MessageType.ResponseIntroducerRegistration:
75 | {
76 | var message = new ResponseIntroducerRegistrationMessage();
77 | message.ReadPayload(e.MessageReader);
78 |
79 | Console.WriteLine(String.Format("Introducer: You have been registered as \"{0}\".", message.RegisteredEndPoint));
80 |
81 | Console.Write("Endpoint of your peer: ");
82 |
83 | var peerEndPoint = Console.ReadLine().Parse();
84 |
85 | Console.WriteLine(String.Format("Requesting an introduction to {0}:{1}...", peerEndPoint.Address, peerEndPoint.Port));
86 | IntroducerSocket.Send(new RequestIntroducerIntroductionMessage() { InternalOwnEndPoint = (IPEndPoint) IntroducerSocket.Socket.LocalEndPoint, ExternalPeerEndPoint = peerEndPoint} );
87 | }
88 | break;
89 | case MessageType.ResponseIntroducerIntroduction:
90 | {
91 | var message = new ResponseIntroducerIntroductionMessage();
92 | message.ReadPayload(e.MessageReader);
93 |
94 | Console.WriteLine(String.Format("Introducer: Your peer's internal endpoint is \"{0}\".", message.InternalPeerEndPoint));
95 | Console.WriteLine(String.Format("Introducer: Your peer's external endpoint is \"{0}\".", message.ExternalPeerEndPoint));
96 |
97 | ConnectSocketInternal = new NetworkPeer();
98 | ConnectSocketInternal.Bind(new IPEndPoint(IPAddress.Any, PORT));
99 | Console.WriteLine(String.Format("Connecting to your peer's internal endpoint..."));
100 | ConnectSocketInternal.OnConnectionSuccessful += (s, e1) => Console.WriteLine("ConnectSocketInternal.OnConnectionSuccessful");
101 | ConnectSocketInternal.Connect(message.InternalPeerEndPoint.Address, message.InternalPeerEndPoint.Port);
102 |
103 | ConnectSocketExternal = new NetworkPeer();
104 | ConnectSocketExternal.Bind(new IPEndPoint(IPAddress.Any, PORT));
105 | Console.WriteLine(String.Format("Connecting to your peer's external endpoint..."));
106 | ConnectSocketExternal.OnConnectionSuccessful += (s, e1) => Console.WriteLine("ConnectSocketExternal.OnConnectionSuccessful");
107 | ConnectSocketExternal.Connect(message.ExternalPeerEndPoint.Address, message.ExternalPeerEndPoint.Port);
108 | }
109 | break;
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching.6.0.ReSharper.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Never
39 |
40 |
41 |
42 |
43 |
44 | False
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/NetworkClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Sockets;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using TcpHolePunching.Messages;
10 |
11 | namespace TcpHolePunching
12 | {
13 | ///
14 | /// A specialized Socket for the Introducer.
15 | ///
16 | public class NetworkClient
17 | {
18 | ///
19 | /// Gets the underlying raw socket.
20 | ///
21 | public Socket Socket { get; private set; }
22 | ///
23 | /// The buffer in which to receive bytes from the transport.
24 | ///
25 | public byte[] Buffer { get; set; }
26 |
27 | ///
28 | /// Occurs after an accepted client has been registered.
29 | ///
30 | public event EventHandler OnConnectionSuccessful;
31 | public event EventHandler OnMessageSent;
32 | public event EventHandler OnMessageReceived;
33 |
34 | public NetworkClient()
35 | {
36 | Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
37 | // Set our special Tcp hole punching socket options
38 | Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
39 | Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
40 | Buffer = new byte[1024];
41 | }
42 |
43 | ///
44 | ///
45 | public void Connect(IPAddress host, int port)
46 | {
47 | Task_BeginConnecting(host, port);
48 | }
49 |
50 | private void Task_BeginConnecting(IPAddress host, int port)
51 | {
52 | var task = Task.Factory.FromAsync(Socket.BeginConnect(host, port, null, null), Socket.EndConnect);
53 | task.ContinueWith(nextTask => Task_OnConnectSuccessful(), TaskContinuationOptions.OnlyOnRanToCompletion);
54 | }
55 |
56 | private void Task_OnConnectSuccessful()
57 | {
58 | Console.WriteLine(String.Format("Connected to {0}.", Socket.RemoteEndPoint));
59 |
60 | Task_BeginReceive();
61 |
62 | // Invoke the event
63 | if (OnConnectionSuccessful != null)
64 | OnConnectionSuccessful(this, new ConnectionAcceptedEventArgs() { Socket = Socket });
65 | }
66 |
67 | public void Send(MessageBase messageBase)
68 | {
69 | // If the registrant exists
70 | if (Socket.Connected)
71 | {
72 | var data = messageBase.GetBytes();
73 | var task = Task.Factory.FromAsync(Socket.BeginSend(data, 0, data.Length, SocketFlags.None, null, Socket), Socket.EndSend);
74 | task.ContinueWith(nextTask => Task_OnSendCompleted(task.Result, data.Length, Socket.RemoteEndPoint, messageBase.MessageType), TaskContinuationOptions.OnlyOnRanToCompletion);
75 | }
76 | }
77 |
78 | private void Task_OnSendCompleted(int numBytesSent, int expectedBytesSent, EndPoint to, MessageType messageType)
79 | {
80 | if (numBytesSent != expectedBytesSent)
81 | Console.WriteLine(String.Format("Warning: Expected to send {0} bytes but actually sent {1}!",
82 | expectedBytesSent, numBytesSent));
83 |
84 | Console.WriteLine(String.Format("Sent a {0} byte {1}Message to {2}.", numBytesSent, messageType, to));
85 |
86 | if (OnMessageSent != null)
87 | OnMessageSent(this, new MessageSentEventArgs() {Length = numBytesSent, To = to});
88 | }
89 |
90 | private void Task_BeginReceive()
91 | {
92 | var task = Task.Factory.FromAsync(Socket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, null, null), Socket.EndReceive);
93 | task.ContinueWith(nextTask =>
94 | {
95 | try
96 | {
97 | Task_OnReceiveCompleted(task.Result);
98 | Task_BeginReceive(); // Receive more data
99 | }
100 | catch (Exception ex)
101 | {
102 | var exceptionMessage = (ex.InnerException != null) ? ex.InnerException.Message : ex.Message;
103 | Console.WriteLine(exceptionMessage);
104 | ShutdownAndClose();
105 | }
106 | }, TaskContinuationOptions.OnlyOnRanToCompletion);
107 | }
108 |
109 | private void Task_OnReceiveCompleted(int numBytesRead)
110 | {
111 | // Build back our MessageReader
112 | var reader = new BufferValueReader(Buffer);
113 | var message = new Message();
114 | message.ReadPayload(reader);
115 | reader.Position = 0;
116 |
117 | Console.WriteLine(String.Format("Received a {0} byte {1}Message from {2}.", numBytesRead, message.MessageType, Socket.RemoteEndPoint));
118 |
119 | if (OnMessageReceived != null)
120 | OnMessageReceived(this, new MessageReceivedEventArgs() { From = (IPEndPoint) Socket.RemoteEndPoint, MessageReader = reader, MessageType = message.MessageType });
121 | }
122 |
123 | ///
124 | /// Only disconnects without shutting down.
125 | ///
126 | public void Disconnect()
127 | {
128 | Socket.Disconnect(true);
129 | }
130 |
131 | ///
132 | /// Explicitly stops sending and receiving, and then closes the socket.
133 | ///
134 | public void ShutdownAndClose()
135 | {
136 | Console.WriteLine("Shutting down socket...");
137 |
138 | try
139 | {
140 | Socket.Shutdown(SocketShutdown.Both);
141 | Socket.Close();
142 | }
143 | catch
144 | {
145 | }
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/NetworkIntroducer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Sockets;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using TcpHolePunching.Messages;
10 |
11 | namespace TcpHolePunching
12 | {
13 | ///
14 | /// A specialized Socket for the Introducer.
15 | ///
16 | public class NetworkIntroducer
17 | {
18 | ///
19 | /// Gets the underlying raw socket.
20 | ///
21 | public Socket Socket { get; private set; }
22 | ///
23 | /// Gets the list of connected clients.
24 | ///
25 | public List Clients { get; private set; }
26 | ///
27 | /// Gets the list of connected clients that have registered with RequestIntroductionRegistrationMessage.
28 | ///
29 | public List Registrants { get; private set; }
30 |
31 | ///
32 | /// Occurs after an accepted client has been registered.
33 | ///
34 | public event EventHandler OnConnectionAccepted;
35 | public event EventHandler OnMessageSent;
36 | public event EventHandler OnMessageReceived;
37 |
38 | public NetworkIntroducer()
39 | {
40 | Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
41 | Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
42 | Clients = new List();
43 | Registrants = new List();
44 | }
45 |
46 | ///
47 | /// Asynchronously accepts a client. Upon accepting the client, the client will automatically be added to
48 | /// a list of registered clients.
49 | ///
50 | public void Listen(EndPoint on)
51 | {
52 | Socket.Bind(on);
53 | Socket.Listen(Int32.MaxValue);
54 | Task_BeginAccepting();
55 | }
56 |
57 | private void Task_BeginAccepting()
58 | {
59 | var task = Task.Factory.FromAsync(Socket.BeginAccept, Socket.EndAccept, null);
60 | task.ContinueWith(nextTask =>
61 | {
62 | Task_OnConnectionAccepted(task.Result);
63 | Task_BeginAccepting(); // Listen for another connection
64 | }, TaskContinuationOptions.OnlyOnRanToCompletion);
65 | }
66 |
67 | private void Task_OnConnectionAccepted(Socket socket)
68 | {
69 | Console.WriteLine(String.Format("Connection to {0} accepted.", socket.RemoteEndPoint));
70 |
71 | // If the registrant was already registered
72 | if (Clients.FindAll(registrant => registrant.RemoteEndPoint == socket.RemoteEndPoint).Any())
73 | {
74 | // Remove the registrant
75 | Clients.RemoveAll(registrant => registrant.RemoteEndPoint == socket.RemoteEndPoint);
76 | }
77 |
78 | // Register the registrant
79 | var newRegistrant = new Client(socket);
80 | Clients.Add(newRegistrant);
81 |
82 | Task_BeginReceive(newRegistrant);
83 |
84 | // Invoke the event
85 | if (OnConnectionAccepted != null)
86 | OnConnectionAccepted(this, new ConnectionAcceptedEventArgs() { Socket = socket } );
87 | }
88 |
89 | public void Send(EndPoint to, MessageBase messageBase)
90 | {
91 | var registrant = Clients.Find(r => r.RemoteEndPoint == to);
92 |
93 | // If the registrant exists
94 | if (registrant != null && registrant.Socket.Connected)
95 | {
96 | var data = messageBase.GetBytes();
97 | var task = Task.Factory.FromAsync(registrant.Socket.BeginSend(data, 0, data.Length, SocketFlags.None, null, Socket), registrant.Socket.EndSend);
98 | task.ContinueWith(nextTask => Task_OnSendCompleted(task.Result, data.Length, registrant.RemoteEndPoint, messageBase.MessageType), TaskContinuationOptions.OnlyOnRanToCompletion);
99 | }
100 | }
101 |
102 | private void Task_OnSendCompleted(int numBytesSent, int expectedBytesSent, EndPoint to, MessageType messageType)
103 | {
104 | if (numBytesSent != expectedBytesSent)
105 | Console.WriteLine(String.Format("Warning: Expected to send {0} bytes but actually sent {1}!",
106 | expectedBytesSent, numBytesSent));
107 |
108 | Console.WriteLine(String.Format("Sent a {0} byte {1}Message to {2}.", numBytesSent, messageType, to));
109 |
110 | if (OnMessageSent != null)
111 | OnMessageSent(this, new MessageSentEventArgs() {Length = numBytesSent, To = to});
112 | }
113 |
114 | private void Task_BeginReceive(Client registrant)
115 | {
116 | var task = Task.Factory.FromAsync(registrant.Socket.BeginReceive(registrant.Buffer, 0, registrant.Buffer.Length, SocketFlags.None, null, null), registrant.Socket.EndReceive);
117 | task.ContinueWith(nextTask =>
118 | {
119 | try
120 | {
121 | Task_OnReceiveCompleted(task.Result, registrant);
122 | Task_BeginReceive(registrant); // Receive more data
123 | }
124 | catch (Exception ex)
125 | {
126 | var exceptionMessage = (ex.InnerException != null) ? ex.InnerException.Message : ex.Message;
127 | Console.WriteLine(exceptionMessage);
128 | ShutdownAndClose();
129 | }
130 | }, TaskContinuationOptions.OnlyOnRanToCompletion);
131 | }
132 |
133 | private void Task_OnReceiveCompleted(int numBytesRead, Client registrant)
134 | {
135 | // Build back our MessageReader
136 | var reader = new BufferValueReader(registrant.Buffer);
137 | var message = new Message();
138 | message.ReadPayload(reader);
139 | reader.Position = 0;
140 |
141 | Console.WriteLine(String.Format("Received a {0} byte {1}Message from {2}.", numBytesRead, message.MessageType, registrant.Socket.RemoteEndPoint));
142 |
143 | if (OnMessageReceived != null)
144 | OnMessageReceived(this, new MessageReceivedEventArgs() { From = (IPEndPoint) registrant.RemoteEndPoint, MessageReader = reader, MessageType = message.MessageType });
145 | }
146 |
147 | ///
148 | /// Explicitly stops sending and receiving, and then closes the socket.
149 | ///
150 | public void ShutdownAndClose()
151 | {
152 | Console.WriteLine("Shutting down sockets...");
153 |
154 | try
155 | {
156 | Socket.Shutdown(SocketShutdown.Both);
157 | Socket.Close();
158 | }
159 | catch
160 | {
161 | }
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/TcpHolePunching/TcpHolePunching/SerializerExtensions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // SerializerExtensions.cs
3 | //
4 | // Author:
5 | // Eric Maupin
6 | //
7 | // Copyright (c) 2011 Eric Maupin
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | using System;
28 | using System.Linq;
29 | using System.Text;
30 | using System.Collections.Generic;
31 |
32 | #if NET_4
33 | using System.Collections.Concurrent;
34 | #endif
35 |
36 | namespace TcpHolePunching
37 | {
38 | public static class SerializerExtensions
39 | {
40 | public static void WriteUniversalDate (this IValueWriter writer, DateTime date)
41 | {
42 | if (writer == null)
43 | throw new ArgumentNullException ("writer");
44 |
45 | if (date.Kind != DateTimeKind.Utc)
46 | date = date.ToUniversalTime();
47 |
48 | writer.WriteInt64 (date.Ticks);
49 | }
50 |
51 | public static DateTime ReadUniversalDate (this IValueReader reader)
52 | {
53 | if (reader == null)
54 | throw new ArgumentNullException ("reader");
55 |
56 | return new DateTime (reader.ReadInt64(), DateTimeKind.Utc);
57 | }
58 |
59 | ///
60 | /// Writes a date value.
61 | ///
62 | public static void WriteDate (this IValueWriter writer, DateTime date)
63 | {
64 | #if !SILVERLIGHT && !WINDOWS_PHONE
65 | WriteLocalDate (writer, date);
66 | #else
67 | writer.WriteInt64 (date.Ticks);
68 | #endif
69 | }
70 |
71 | ///
72 | /// Reads a date value.
73 | ///
74 | public static DateTime ReadDate (this IValueReader reader)
75 | {
76 | #if !SILVERLIGHT && !WINDOWS_PHONE
77 | return ReadLocalDate (reader).Item2;
78 | #else
79 | return new DateTime (reader.ReadInt64(), DateTimeKind.Unspecified);
80 | #endif
81 | }
82 |
83 | #if !SILVERLIGHT && !WINDOWS_PHONE
84 | public static void WriteLocalDate (this IValueWriter writer, DateTime date)
85 | {
86 | WriteLocalDate (writer, date, TimeZoneInfo.Local);
87 | }
88 |
89 | public static void WriteLocalDate (this IValueWriter writer, DateTime date, TimeZoneInfo timeZone)
90 | {
91 | if (writer == null)
92 | throw new ArgumentNullException ("writer");
93 |
94 | writer.WriteString (timeZone.ToSerializedString());
95 | writer.WriteInt64 (date.ToLocalTime().Ticks);
96 | }
97 |
98 | public static Tuple ReadLocalDate (this IValueReader reader)
99 | {
100 | if (reader == null)
101 | throw new ArgumentNullException ("reader");
102 |
103 | return new Tuple (TimeZoneInfo.FromSerializedString (reader.ReadString()),
104 | new DateTime (reader.ReadInt64(), DateTimeKind.Unspecified));
105 | }
106 | #endif
107 |
108 | public static void WriteString (this IValueWriter writer, string value)
109 | {
110 | if (writer == null)
111 | throw new ArgumentNullException ("writer");
112 |
113 | writer.WriteString (Encoding.UTF8, value);
114 | }
115 |
116 | public static string ReadString (this IValueReader reader)
117 | {
118 | if (reader == null)
119 | throw new ArgumentNullException ("reader");
120 |
121 | return reader.ReadString (Encoding.UTF8);
122 | }
123 |
124 | public static void WriteEnumerable (this IValueWriter writer, IEnumerable enumerable)
125 | where T : ISerializable
126 | {
127 | if (writer == null)
128 | throw new ArgumentNullException ("writer");
129 | if (enumerable == null)
130 | throw new ArgumentNullException ("enumerable");
131 |
132 | T[] elements = enumerable.ToArray();
133 | writer.WriteInt32 (elements.Length);
134 | for (int i = 0; i < elements.Length; ++i)
135 | elements[i].Serialize (writer);
136 | }
137 |
138 | public static void WriteEnumerable (this IValueWriter writer, ISerializer serializer, IEnumerable enumerable)
139 | {
140 | if (writer == null)
141 | throw new ArgumentNullException ("writer");
142 | if (serializer == null)
143 | throw new ArgumentNullException ("serializer");
144 | if (enumerable == null)
145 | throw new ArgumentNullException ("enumerable");
146 |
147 | T[] elements = enumerable.ToArray();
148 | writer.WriteInt32 (elements.Length);
149 | for (int i = 0; i < elements.Length; ++i)
150 | serializer.Serialize (writer, elements[i]);
151 | }
152 |
153 | public static IEnumerable ReadEnumerable (this IValueReader reader, Func elementFactory)
154 | where T : ISerializable
155 | {
156 | if (reader == null)
157 | throw new ArgumentNullException ("reader");
158 | if (elementFactory == null)
159 | throw new ArgumentNullException ("elementFactory");
160 |
161 | int length = reader.ReadInt32();
162 | T[] elements = new T[length];
163 | for (int i = 0; i < elements.Length; ++i)
164 | (elements[i] = elementFactory()).Deserialize (reader);
165 |
166 | return elements;
167 | }
168 |
169 | public static IEnumerable ReadEnumerable (this IValueReader reader, ISerializer serializer)
170 | {
171 | if (reader == null)
172 | throw new ArgumentNullException ("reader");
173 | if (serializer == null)
174 | throw new ArgumentNullException ("serializer");
175 |
176 | int length = reader.ReadInt32();
177 | T[] elements = new T[length];
178 | for (int i = 0; i < elements.Length; ++i)
179 | elements[i] = serializer.Deserialize (reader);
180 |
181 | return elements;
182 | }
183 |
184 | public static IEnumerable ReadEnumerable (this IValueReader reader, Func elementFactory)
185 | {
186 | if (reader == null)
187 | throw new ArgumentNullException ("reader");
188 | if (elementFactory == null)
189 | throw new ArgumentNullException ("elementFactory");
190 |
191 | int length = reader.ReadInt32();
192 | T[] elements = new T[length];
193 | for (int i = 0; i < elements.Length; ++i)
194 | elements[i] = elementFactory (reader);
195 |
196 | return elements;
197 | }
198 |
199 | public static void Write (this IValueWriter writer, object element, Type serializeAs)
200 | {
201 | Write (writer, element, new FixedSerializer (serializeAs));
202 | }
203 |
204 | public static void Write (this IValueWriter writer, object element, ISerializer serializer)
205 | {
206 | if (writer == null)
207 | throw new ArgumentNullException ("writer");
208 | if (element == null)
209 | throw new ArgumentNullException ("element");
210 | if (serializer == null)
211 | throw new ArgumentNullException ("serializer");
212 |
213 | serializer.Serialize (writer, element);
214 | }
215 |
216 | public static void Write (this IValueWriter writer, T element)
217 | {
218 | Write (writer, element, Serializer.Default);
219 | }
220 |
221 | public static void Write (this IValueWriter writer, T element, ISerializer serializer)
222 | {
223 | if (writer == null)
224 | throw new ArgumentNullException ("writer");
225 | if (serializer == null)
226 | throw new ArgumentNullException ("serializer");
227 |
228 | serializer.Serialize (writer, element);
229 | }
230 |
231 | public static T Read (this IValueReader reader)
232 | {
233 | if (reader == null)
234 | throw new ArgumentNullException ("reader");
235 |
236 | return Read (reader, Serializer.Default);
237 | }
238 |
239 | public static T Read (this IValueReader reader, ISerializer serializer)
240 | {
241 | if (reader == null)
242 | throw new ArgumentNullException ("reader");
243 | if (serializer == null)
244 | throw new ArgumentNullException ("serializer");
245 |
246 | return serializer.Deserialize (reader);
247 | }
248 |
249 | public static object Read (this IValueReader reader)
250 | {
251 | return Read