summaryrefslogtreecommitdiff
path: root/doc/classes/DTLSServer.xml
blob: 8e85c12ad1c4026e879e55d64ddd14e01db9b1d0 (plain)
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
39
40
41
42
43
44
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<?xml version="1.0" encoding="UTF-8" ?>
<class name="DTLSServer" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
	<brief_description>
		Helper class to implement a DTLS server.
	</brief_description>
	<description>
		This class is used to store the state of a DTLS server. Upon [method setup] it converts connected [PacketPeerUDP] to [PacketPeerDTLS] accepting them via [method take_connection] as DTLS clients. Under the hood, this class is used to store the DTLS state and cookies of the server. The reason of why the state and cookies are needed is outside of the scope of this documentation.
		Below a small example of how to use it:
		[codeblocks]
		[gdscript]
		# server_node.gd
		extends Node

		var dtls := DTLSServer.new()
		var server := UDPServer.new()
		var peers = []

		func _ready():
		    server.listen(4242)
		    var key = load("key.key") # Your private key.
		    var cert = load("cert.crt") # Your X509 certificate.
		    dtls.setup(key, cert)

		func _process(delta):
		    while server.is_connection_available():
		        var peer: PacketPeerUDP = server.take_connection()
		        var dtls_peer: PacketPeerDTLS = dtls.take_connection(peer)
		        if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:
		            continue # It is normal that 50% of the connections fails due to cookie exchange.
		        print("Peer connected!")
		        peers.append(dtls_peer)

		    for p in peers:
		        p.poll() # Must poll to update the state.
		        if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
		            while p.get_available_packet_count() &gt; 0:
		                print("Received message from client: %s" % p.get_packet().get_string_from_utf8())
		                p.put_packet("Hello DTLS client".to_utf8_buffer())
		[/gdscript]
		[csharp]
		// ServerNode.cs
		using Godot;

		public partial class ServerNode : Node
		{
		    private DtlsServer _dtls = new DtlsServer();
		    private UdpServer _server = new UdpServer();
		    private Godot.Collections.Array&lt;PacketPeerDTLS&gt; _peers = new Godot.Collections.Array&lt;PacketPeerDTLS&gt;();

		    public override void _Ready()
		    {
		        _server.Listen(4242);
		        var key = GD.Load&lt;CryptoKey&gt;("key.key"); // Your private key.
		        var cert = GD.Load&lt;X509Certificate&gt;("cert.crt"); // Your X509 certificate.
		        _dtls.Setup(key, cert);
		    }

		    public override void _Process(double delta)
		    {
		        while (Server.IsConnectionAvailable())
		        {
		            PacketPeerUDP peer = _server.TakeConnection();
		            PacketPeerDTLS dtlsPeer = _dtls.TakeConnection(peer);
		            if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking)
		            {
		                continue; // It is normal that 50% of the connections fails due to cookie exchange.
		            }
		            GD.Print("Peer connected!");
		            _peers.Add(dtlsPeer);
		        }

		        foreach (var p in _peers)
		        {
		            p.Poll(); // Must poll to update the state.
		            if (p.GetStatus() == PacketPeerDtls.Status.Connected)
		            {
		                while (p.GetAvailablePacketCount() &gt; 0)
		                {
		                    GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}");
		                    p.PutPacket("Hello DTLS Client".ToUtf8Buffer());
		                }
		            }
		        }
		    }
		}
		[/csharp]
		[/codeblocks]
		[codeblocks]
		[gdscript]
		# client_node.gd
		extends Node

		var dtls := PacketPeerDTLS.new()
		var udp := PacketPeerUDP.new()
		var connected = false

		func _ready():
		    udp.connect_to_host("127.0.0.1", 4242)
		    dtls.connect_to_peer(udp, false) # Use true in production for certificate validation!

		func _process(delta):
		    dtls.poll()
		    if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
		        if !connected:
		            # Try to contact server
		            dtls.put_packet("The answer is... 42!".to_utf8_buffer())
		        while dtls.get_available_packet_count() &gt; 0:
		            print("Connected: %s" % dtls.get_packet().get_string_from_utf8())
		            connected = true
		[/gdscript]
		[csharp]
		// ClientNode.cs
		using Godot;
		using System.Text;

		public partial class ClientNode : Node
		{
		    private PacketPeerDtls _dtls = new PacketPeerDtls();
		    private PacketPeerUdp _udp = new PacketPeerUdp();
		    private bool _connected = false;

		    public override void _Ready()
		    {
		        _udp.ConnectToHost("127.0.0.1", 4242);
		        _dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation!
		    }

		    public override void _Process(double delta)
		    {
		        _dtls.Poll();
		        if (_dtls.GetStatus() == PacketPeerDtls.Status.Connected)
		        {
		            if (!_connected)
		            {
		                // Try to contact server
		                _dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer());
		            }
		            while (_dtls.GetAvailablePacketCount() &gt; 0)
		            {
		                GD.Print($"Connected: {_dtls.GetPacket().GetStringFromUtf8()}");
		                _connected = true;
		            }
		        }
		    }
		}
		[/csharp]
		[/codeblocks]
	</description>
	<tutorials>
	</tutorials>
	<methods>
		<method name="setup">
			<return type="int" enum="Error" />
			<param index="0" name="server_options" type="TLSOptions" />
			<description>
				Setup the DTLS server to use the given [param server_options]. See [method TLSOptions.server].
			</description>
		</method>
		<method name="take_connection">
			<return type="PacketPeerDTLS" />
			<param index="0" name="udp_peer" type="PacketPeerUDP" />
			<description>
				Try to initiate the DTLS handshake with the given [param udp_peer] which must be already connected (see [method PacketPeerUDP.connect_to_host]).
				[b]Note:[/b] You must check that the state of the return PacketPeerUDP is [constant PacketPeerDTLS.STATUS_HANDSHAKING], as it is normal that 50% of the new connections will be invalid due to cookie exchange.
			</description>
		</method>
	</methods>
</class>