diff --git a/client/Stream/Stream.gd b/client/Stream/Stream.gd index 109b456..4cfe7b6 100644 --- a/client/Stream/Stream.gd +++ b/client/Stream/Stream.gd @@ -28,14 +28,31 @@ enum StreamState { } var stream_status = StreamState.END -@export var server_ip:String = "localhost": - set = set_server_ip, get = get_server_ip +enum XMPPState { + NONE, # Nothing is configured + TRY_CONNECT_SERVER, # Try to connect to server + CONNECTED_SERVER, # Confirmed we are connected to server + INTIALIZE, # Initialize first connection with server + INTIALIZED, # when initialize is finished + FEATURE_SERVER, # We received Feature (TLS ?) + START_TLS, # We start TLS + WAIT_TLS, # Wait TLS Done + MISSING_TLS, # Missing feature TLS -> wait 30min and retry + STARTED_TLS, # TLS connection is done + AUTHENTICATE_STEP_1, # Launch authenticate + AUTHENTICATE_STEP_2, # Launch authenticate + AUTHENTICATE_STEP_3, # Launch authenticate + AUTHENTICATED, # We finished authenticate +} -func set_server_ip(value:String): - server_ip = value +@export var server_xmpp_name:String = "localhost": + set = set_server_xmpp_name, get = get_server_xmpp_name + +func set_server_xmpp_name(value:String): + server_xmpp_name = value -func get_server_ip() -> String: - return server_ip +func get_server_xmpp_name() -> String: + return server_xmpp_name @export var port_number:int = 5222: set = set_port_number, get = get_port_number @@ -79,28 +96,321 @@ func get_locale() -> String: set(value): xmppclient = value +const MAX_WAIT_CONNECTING:float = 60.0 +const MAX_WAIT_MISSING_TLS:float = 1800.0 + var try_connect:int = 0 -var count_connecting_time:float = 0 +var count_connecting_time:float = MAX_WAIT_CONNECTING var partial_stanza:String = "" var tcp_peer:StreamPeerTCP = StreamPeerTCP.new() var ssl_peer:StreamPeerTLS = StreamPeerTLS.new() var tgt_peer = null var status:StreamState = StreamState.END +var xmpp_state = XMPPState.NONE +var authentication_methods = [] + +func reinit_stream(): + if ssl_peer != null: + ssl_peer.disconnect_from_stream() + else: + ssl_peer = StreamPeerTLS.new() + if tcp_peer != null: + tcp_peer.disconnect_from_host() + else: + tcp_peer = StreamPeerTCP.new() + tgt_peer = tcp_peer + start_stream() + stream_status = self.StreamState.START -func _init(): +func _init() -> void: var language = OS.get_locale() set_locale(language) tgt_peer = tcp_peer + # reinit_stream() -func _process(delta): - #Global.msg_info("TCP:%d", [tcp_peer.get_status()]) - print(server_ip, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status) -# if tcp_peer.get_status() == StreamPeerTCP.STATUS_NONE and stream_status == self.StreamState.TLS: -# #negotiate_tls() -# print("negotiate_tls") -# pass - if (tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED) : + +func _process(delta) -> void: + print(server_xmpp_name, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status, " / xmpp_state:", XMPPState.keys()[xmpp_state]) + if xmppclient == false: + return + # Wait MAX_WAIT_MISSING_TLS (s) if server can't negociate with TLS + if xmpp_state == XMPPState.MISSING_TLS: + if count_connecting_time >= MAX_WAIT_MISSING_TLS: + xmpp_state = XMPPState.NONE + else: + count_connecting_time += delta + elif xmpp_state == XMPPState.NONE: + if count_connecting_time >= MAX_WAIT_CONNECTING: + xmpp_state = XMPPState.TRY_CONNECT_SERVER + if ssl_peer.get_status() != StreamPeerTLS.STATUS_DISCONNECTED: + ssl_peer.disconnect_from_stream() + if tcp_peer.get_status() != StreamPeerTCP.STATUS_NONE: + tcp_peer.disconnect_from_host() + else: + count_connecting_time += delta + elif xmpp_state == XMPPState.TRY_CONNECT_SERVER: + if tcp_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED: + xmpp_state = XMPPState.CONNECTED_SERVER + count_connecting_time = MAX_WAIT_CONNECTING + elif count_connecting_time >= MAX_WAIT_CONNECTING: + var res = tcp_peer.connect_to_host(server_xmpp_name, port_number) + if res == OK: + send_msg_debug.emit("Send connect_to_host : ok") + #stream_status = self.StreamState.END + #xmpp_state = XMPPState.CONNECTED_SERVER + count_connecting_time = 0 + else: + send_msg_error.emit("Error to connect to XMPP server (return:%d)" % res) + xmpp_state = XMPPState.NONE + count_connecting_time = 0 + else: + if (tcp_peer.has_method("poll")): + tcp_peer.poll() + count_connecting_time += delta + elif xmpp_state == XMPPState.CONNECTED_SERVER: + if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED: + xmpp_state = XMPPState.NONE + count_connecting_time = 0 + return + if count_connecting_time >= MAX_WAIT_CONNECTING: + count_connecting_time = 0 + send_msg_debug.emit("send_tcp_initialize_xmpp") + send_tcp_initialize_xmpp() + else: + count_connecting_time += delta + if (tcp_peer.has_method("poll")): + tcp_peer.poll() + if tcp_peer.get_available_bytes()>0: + var response = tcp_peer.get_string(tcp_peer.get_available_bytes()) + send_msg_debug.emit("Stream: response: " + response) + response = remove_stream_header(response) + if not analyze_error(response): + if analyze_feature_starttls(response): + xmpp_state = XMPPState.START_TLS + else: + count_connecting_time = 0 + xmpp_state = XMPPState.MISSING_TLS + elif xmpp_state == XMPPState.START_TLS: + if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED: + xmpp_state = XMPPState.NONE + count_connecting_time = 0 + return + if count_connecting_time >= MAX_WAIT_CONNECTING: + count_connecting_time = 0 + xmpp_state = XMPPState.NONE + else: + count_connecting_time += delta + if (tcp_peer.has_method("poll")): + tcp_peer.poll() + if tcp_peer.get_available_bytes()>0: + var response = tcp_peer.get_string(tcp_peer.get_available_bytes()) + send_msg_debug.emit("Stream: response: " + response) + response = remove_stream_header(response) + if response.begins_with("= MAX_WAIT_CONNECTING: + count_connecting_time = 0 + xmpp_state = XMPPState.MISSING_TLS + else: + count_connecting_time += delta + else: + count_connecting_time = 0 + xmpp_state = XMPPState.MISSING_TLS + elif xmpp_state == XMPPState.STARTED_TLS: + if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED: + xmpp_state = XMPPState.NONE + count_connecting_time = 0 + return + if ssl_peer.get_status() != StreamPeerTLS.STATUS_CONNECTED: + xmpp_state = XMPPState.NONE + count_connecting_time = 0 + return + if count_connecting_time >= MAX_WAIT_CONNECTING: + count_connecting_time = 0 + send_msg_debug.emit("send_ssl_initialize_xmpp") + send_ssl_initialize_xmpp() + else: + count_connecting_time += delta + if (ssl_peer.has_method("poll")): + ssl_peer.poll() + if ssl_peer.get_available_bytes()>0: + var response = ssl_peer.get_string(ssl_peer.get_available_bytes()) + send_msg_debug.emit("Stream: response: " + response) + response = remove_stream_header(response) + if not analyze_error(response): + if analyze_feature_mechanisms(response): + if authentication_methods.size() > 0: + count_connecting_time = MAX_WAIT_CONNECTING + xmpp_state = XMPPState.AUTHENTICATE_STEP_1 + #send_msg_debug.emit("AUTHENTICATE_STEP_1") +# elif response.begins_with("= MAX_WAIT_CONNECTING: + count_connecting_time = 0 + negotiate_ssl_sasl(authentication_methods) + else: + count_connecting_time += delta + if (ssl_peer.has_method("poll")): + ssl_peer.poll() + if ssl_peer.get_available_bytes()>0: + var response = ssl_peer.get_string(ssl_peer.get_available_bytes()) + send_msg_debug.emit("Stream: response: " + response) + response = remove_stream_header(response) + if response.begins_with(" bool: + if response.begins_with(" bool: + if response.begins_with(" bool: + if response.begins_with(" 0): + var tmp:String = "" + var sep:String = "" + for item in authentication_methods: + tmp += sep + item + sep = ", " + send_msg_debug.emit("Stream: authentication methods: " + tmp) + #negotiate_ssl_sasl(authentication_methods) + #stream_status = self.StreamState.AUTHENTICATE + return true + #negotiate_ssl_sasl(authentication_methods) + return false + + +func send_tcp_initialize_xmpp() -> void: + """ Send the stream header. + Needs to be done several times over stream negotiation. + """ + var message:String = "" + \ + " " + # " from=\"" + account_name + "\" " + \ + # + locale + "'" + + print(message) + send_tcp_string(message) + + +func send_ssl_initialize_xmpp() -> void: + """ Send the stream header. + Needs to be done several times over stream negotiation. + """ + var server_name = account_name.split("@")[-1] + var message:String = "" + \ + " " + # " from=\"" + account_name + "\" " + \ + # + locale + "'" + + print(message) + send_ssl_string(message) + + + +func negotiate_ssl_sasl(authentication_methods : Array) -> bool: + if ( authentication_methods.has("PLAIN")): + send_msg_debug.emit("Stream: sending request for plain") + var msg:PackedByteArray = PackedByteArray() + msg.push_back(0) + var t = account_name.split("@")[0] + msg += t.to_ascii_buffer() + #msg += conv_string_to_PackedByteArray(account_name.split("@")[0]) + msg.push_back(0) + msg += password.to_ascii_buffer() + var auth_account:String = Marshalls.raw_to_base64(msg) + var request_sasl:String = "" + auth_account + "" + send_ssl_string(request_sasl) + return true + else: + send_msg_error.emit("Impossible to authenticate (unknown protocol)") + return false + + +# +# +# + +func connect_to_server_xmpp() -> void: + var res = tcp_peer.connect_to_host(server_xmpp_name, port_number) + if res == OK: + count_connecting_time = 0 + stream_status = self.StreamState.END + set_process(true) + tgt_peer = tcp_peer + +func _process_old(delta) -> void: + print(server_xmpp_name, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status) + if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED: print("STATUS_CONNECTED:", delta) if (tgt_peer.has_method("poll")): tgt_peer.poll() @@ -109,15 +419,15 @@ func _process(delta): send_msg_debug.emit("Stream: response: " + response) if stream_status == self.StreamState.STANZA: #collect_stanza(remove_stream_header(response)) - Global.msg_info("", []) print("collect_stanza") else: print("stream_process") stream_process(remove_stream_header(response)) # print(remove_stream_header(response)) elif stream_status == self.StreamState.END: - start_stream() - stream_status = self.StreamState.START + reinit_stream() + #start_stream() + #stream_status = self.StreamState.START count_connecting_time = 0 if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTING: print("STATUS_CONNECTING:", delta) @@ -132,6 +442,7 @@ func _process(delta): set_process(false) # stop listening for packets try_connect = 20 stream_status = self.StreamState.END + reinit_stream() if tgt_peer.get_status() == StreamPeerTCP.STATUS_NONE and xmppclient: print("connect_to_server:", xmppclient) connect_to_server() @@ -144,7 +455,7 @@ func connect_to_server(): pass if try_connect == 0 and tcp_peer.get_status() == StreamPeerTCP.STATUS_NONE: #print("-> ", server_ip, ":", port_number, "/" , tcp_peer.get_status()) - var res = tcp_peer.connect_to_host(server_ip, port_number) + var res = tcp_peer.connect_to_host(server_xmpp_name, port_number) if res == OK: count_connecting_time = 0 stream_status = self.StreamState.END @@ -162,6 +473,18 @@ func send_string(stanza:String) ->void: tgt_peer.put_data(stanza.to_utf8_buffer()) +func send_tcp_string(stanza:String) ->void: + """ Send a string in the appropriate encoding. """ + send_msg_debug.emit("Sending data: '%'".format([stanza], "%")) + tcp_peer.put_data(stanza.to_utf8_buffer()) + + +func send_ssl_string(stanza:String) ->void: + """ Send a string in the appropriate encoding. """ + send_msg_debug.emit("Sending data: '%'".format([stanza], "%")) + ssl_peer.put_data(stanza.to_utf8_buffer()) + + func conv_string_to_PackedByteArray(message:String) -> PackedByteArray: return message.to_ascii_buffer() @@ -277,7 +600,7 @@ func stream_process(response :String = "") -> void: print("Mystery stream status: "+str(stream_status)) -func negotiate_tls() -> void: +func negotiate_tls() -> bool: #var ssl_peer = StreamPeerTLS.new() # I am unsure how to validate the ssl certificate for an unknown host? #var ssl_succes = FAILED @@ -298,29 +621,31 @@ func negotiate_tls() -> void: print("get_status:", ssl_peer.get_status()) print("-----") #stream_status == StreamState.START + return true else: send_msg_error.emit("SSL failed, error %".format([ssl_succes], "%")) + return false func negotiate_sasl(authentication_methods : Array) -> void: - if (!authentication_methods.has("PLAIN")): - end_stream() - send_msg_debug.emit("Stream: sending request for plain") - var msg:PackedByteArray = PackedByteArray() - msg.push_back(0) - var t = account_name.split("@")[0] - msg += t.to_ascii_buffer() - #msg += conv_string_to_PackedByteArray(account_name.split("@")[0]) - msg.push_back(0) - msg += password.to_ascii_buffer() - print("7:", msg) - - var auth_account:String = Marshalls.raw_to_base64(msg) - var request_sasl:String = "" + auth_account + "" - send_string(request_sasl) + send_string(request_sasl) + else: + send_msg_error.emit("Impossible to authenticate (unknown protocol)") + end_stream() func end_stream() -> void: diff --git a/client/scenes/main.gd b/client/scenes/main.gd index 86975cb..4622690 100644 --- a/client/scenes/main.gd +++ b/client/scenes/main.gd @@ -35,7 +35,7 @@ func _ready(): Multi.update_my_position.connect(_on_update_me) Multi.update_player_position.connect(_on_update_player) Multi.remove_player.connect(_on_remove_player) - Stream.set_server_ip("localhost") + Stream.set_server_xmpp_name("localhost") Stream.set_port_number(5222) Stream.send_msg_debug.connect(show_stream_debug) Stream.send_msg_error.connect(show_stream_error)