@@ -829,6 +829,99 @@ pub async fn get_tunnel_or_location_name(
829
829
}
830
830
}
831
831
832
+ // Check if location/tunnel is connected and WireGuard Windows service is running.
833
+ // `id`: location or tunnel Id
834
+ // `name`: location or tunnel name
835
+ #[ cfg( target_os = "windows" ) ]
836
+ async fn check_connection (
837
+ service_manager : & ServiceManager ,
838
+ id : Id ,
839
+ name : & str ,
840
+ connection_type : ConnectionType ,
841
+ app_handle : AppHandle ,
842
+ ) -> Result < ( ) , Error > {
843
+ let appstate = app_handle. state :: < AppState > ( ) ;
844
+ let interface_name = get_interface_name ( name) ;
845
+ let service_name = format ! ( "WireGuardTunnel${}" , name) ;
846
+ let service = match service_manager. open_service ( & service_name, ServiceAccess :: QUERY_CONFIG ) {
847
+ Ok ( service) => service,
848
+ Err ( windows_service:: Error :: Winapi ( err) )
849
+ if err. raw_os_error ( ) == Some ( ERROR_SERVICE_DOES_NOT_EXIST as i32 ) =>
850
+ {
851
+ debug ! ( "WireGuard tunnel {interface_name} is not installed, nothing to synchronize" ) ;
852
+ return Ok ( ( ) ) ;
853
+ }
854
+ Err ( err) => {
855
+ warn ! (
856
+ "Failed to open service {service_name} for interface {interface_name} while \
857
+ synchronizing active connections. This may cause the {connection_type} {name} \
858
+ state to display incorrectly in the client. Reconnect to it manually to fix it. \
859
+ Error: {err}"
860
+ ) ;
861
+ return Ok ( ( ) ) ;
862
+ }
863
+ } ;
864
+ match service. query_status ( ) {
865
+ Ok ( status) => {
866
+ // Only point where we don't return and continue with the rest of the code below.
867
+ if status. current_state == ServiceState :: Running {
868
+ debug ! ( "WireGuard tunnel {interface_name} is running." ) ;
869
+ } else {
870
+ debug ! (
871
+ "WireGuard tunnel {interface_name} is not running, status code: {:?}. Refer to \
872
+ Windows documentation for more information about the code.",
873
+ status. current_state
874
+ ) ;
875
+ return Ok ( ( ) ) ;
876
+ }
877
+ }
878
+ Err ( err) => {
879
+ warn ! (
880
+ "Failed to query service status for interface {interface_name} while synchronizing \
881
+ active connections. This may cause the {connection_type} {name} state to display \
882
+ incorrectly in the client. Reconnect to it manually to fix it. Error: {err}",
883
+ ) ;
884
+ return Ok ( ( ) ) ;
885
+ }
886
+ }
887
+
888
+ if appstate
889
+ . find_connection ( id, connection_type)
890
+ . await
891
+ . is_some ( )
892
+ {
893
+ debug ! ( "{connection_type} {name} has already a connected state, skipping synchronization" ) ;
894
+ return Ok ( ( ) ) ;
895
+ }
896
+
897
+ appstate
898
+ . add_connection ( id, & interface_name, connection_type)
899
+ . await ;
900
+
901
+ debug ! ( "Sending event informing the frontend that a new connection has been created." ) ;
902
+ app_handle. emit_all (
903
+ CONNECTION_CHANGED ,
904
+ Payload {
905
+ message : "Created new connection" . into ( ) ,
906
+ } ,
907
+ ) ?;
908
+ debug ! ( "Event informing the frontend that a new connection has been created sent." ) ;
909
+
910
+ debug ! ( "Spawning service log watcher for {connection_type} {name}..." ) ;
911
+ spawn_log_watcher_task (
912
+ app_handle. clone ( ) ,
913
+ id,
914
+ interface_name,
915
+ connection_type,
916
+ Level :: DEBUG ,
917
+ None ,
918
+ )
919
+ . await ?;
920
+ debug ! ( "Service log watcher for {connection_type} {name} spawned." ) ;
921
+
922
+ Ok ( ( ) )
923
+ }
924
+
832
925
// TODO: Move the connection handling to a seperate, common function,
833
926
// so `handle_connection_for_location` and `handle_connection_for_tunnel` are not
834
927
// partially duplicated here.
@@ -837,7 +930,7 @@ pub async fn sync_connections(app_handle: &AppHandle) -> Result<(), Error> {
837
930
debug ! ( "Synchronizing active connections with the systems' state..." ) ;
838
931
let appstate = app_handle. state :: < AppState > ( ) ;
839
932
let all_locations = Location :: all ( & appstate. db ) . await ?;
840
- let service_control_manager =
933
+ let service_manager =
841
934
ServiceManager :: local_computer ( None :: < & str > , ServiceManagerAccess :: CONNECT ) . map_err (
842
935
|err| {
843
936
error ! (
@@ -852,190 +945,32 @@ pub async fn sync_connections(app_handle: &AppHandle) -> Result<(), Error> {
852
945
} ,
853
946
) ?;
854
947
855
- debug ! ( "Opened service control manager, starting to synchronize active connections for locations..." ) ;
856
- // Go through all locations and check if they are connected (if the windows service is running)
948
+ debug ! ( "Opened service control manager. Synchronizing active connections for locations..." ) ;
949
+ // Go through all locations and check if they are connected and Windows service is running.
857
950
// If we encounter any errors, continue with the next iteration of the loop, it's not a big deal
858
- // if we skip some locations, as the user can always reconnect to them manually
951
+ // if we skip some locations, as the user can always reconnect to them manually.
859
952
for location in all_locations {
860
- let interface_name = get_interface_name ( & location. name ) ;
861
- let service_name = format ! ( "WireGuardTunnel${}" , location. name) ;
862
- let service = match service_control_manager
863
- . open_service ( & service_name, ServiceAccess :: QUERY_CONFIG )
864
- {
865
- Ok ( service) => service,
866
- Err ( windows_service:: Error :: Winapi ( err) )
867
- if err. raw_os_error ( ) == Some ( ERROR_SERVICE_DOES_NOT_EXIST as i32 ) =>
868
- {
869
- debug ! (
870
- "WireGuard tunnel {} is not installed, nothing to synchronize" ,
871
- interface_name
872
- ) ;
873
- continue ;
874
- }
875
- Err ( err) => {
876
- warn ! (
877
- "Failed to open service {service_name} for interface {interface_name} while \
878
- synchronizing active connections. This may cause the location {} state to \
879
- display incorrectly in the client. Reconnect to it manually to fix it. \
880
- Error: {err}",
881
- location. name
882
- ) ;
883
- continue ;
884
- }
885
- } ;
886
- match service. query_status ( ) {
887
- Ok ( status) => {
888
- // Only point where we don't jump to the next iteration of the loop and continue with the rest of the code below the match
889
- if status. current_state == ServiceState :: Running {
890
- debug ! ( "WireGuard tunnel {} is running, " , interface_name) ;
891
- } else {
892
- debug ! (
893
- "WireGuard tunnel {} is not running, status code: {:?}. Refer to \
894
- Windows documentation for more information about the code.",
895
- interface_name, status. current_state
896
- ) ;
897
- continue ;
898
- }
899
- }
900
- Err ( err) => {
901
- warn ! (
902
- "Failed to query service status for interface {} while synchronizing active \
903
- connections. This may cause the location {} state to display incorrectly in \
904
- the client. Reconnect to it manually to fix it. Error: {err}",
905
- interface_name, location. name
906
- ) ;
907
- continue ;
908
- }
909
- }
910
-
911
- if appstate
912
- . find_connection ( location. id , ConnectionType :: Location )
913
- . await
914
- . is_some ( )
915
- {
916
- debug ! (
917
- "Location {} has already a connected state, skipping synchronization" ,
918
- location. name
919
- ) ;
920
- continue ;
921
- }
922
-
923
- appstate
924
- . add_connection ( location. id , & interface_name, ConnectionType :: Location )
925
- . await ;
926
-
927
- debug ! ( "Sending event informing the frontend that a new connection has been created." ) ;
928
- app_handle. emit_all (
929
- CONNECTION_CHANGED ,
930
- Payload {
931
- message : "Created new connection" . into ( ) ,
932
- } ,
933
- ) ?;
934
- debug ! ( "Event informing the frontend that a new connection has been created sent." ) ;
935
-
936
- debug ! ( "Spawning service log watcher for location {}..." , location) ;
937
- spawn_log_watcher_task (
938
- app_handle. clone ( ) ,
953
+ check_connection (
954
+ & service_manager,
939
955
location. id ,
940
- interface_name ,
956
+ & location . name ,
941
957
ConnectionType :: Location ,
942
- Level :: DEBUG ,
943
- None ,
958
+ app_handle. clone ( ) ,
944
959
)
945
960
. await ?;
946
- debug ! ( "Service log watcher for location {} spawned." , location) ;
947
961
}
948
962
949
963
debug ! ( "Synchronizing active connections for tunnels..." ) ;
950
964
// Do the same for tunnels
951
965
for tunnel in Tunnel :: all ( & appstate. db ) . await ? {
952
- let interface_name = get_interface_name ( & tunnel. name ) ;
953
- let service_name = format ! ( "WireGuardTunnel${}" , interface_name) ;
954
- let service = match service_control_manager
955
- . open_service ( & service_name, ServiceAccess :: QUERY_CONFIG )
956
- {
957
- Ok ( service) => service,
958
- Err ( windows_service:: Error :: Winapi ( err) )
959
- if err. raw_os_error ( ) == Some ( ERROR_SERVICE_DOES_NOT_EXIST as i32 ) =>
960
- {
961
- debug ! (
962
- "WireGuard tunnel {} is not installed, nothing to synchronize" ,
963
- interface_name
964
- ) ;
965
- continue ;
966
- }
967
- Err ( err) => {
968
- error ! (
969
- "Failed to open service {service_name} for interface {interface_name}. \
970
- This may cause the tunnel {} state to display incorrectly in the \
971
- client. Reconnect to it manually to fix it. Error: {err}",
972
- tunnel. name
973
- ) ;
974
- continue ;
975
- }
976
- } ;
977
- match service. query_status ( ) {
978
- Ok ( status) => {
979
- // Only point where we don't jump to the next iteration of the loop and continue with the rest of the code below the match
980
- if status. current_state == ServiceState :: Running {
981
- debug ! ( "WireGuard tunnel {} is running" , interface_name) ;
982
- } else {
983
- debug ! (
984
- "WireGuard tunnel {} is not running, status code: {:?}. Refer to Windows \
985
- documentation for more information about the code.",
986
- interface_name, status. current_state
987
- ) ;
988
- continue ;
989
- }
990
- }
991
- Err ( err) => {
992
- warn ! (
993
- "Failed to query service status for interface {}. \
994
- This may cause the tunnel {} state to display incorrectly in the client. \
995
- Reconnect to it manually to fix it. Error: {err}",
996
- interface_name, tunnel. name
997
- ) ;
998
- continue ;
999
- }
1000
- }
1001
-
1002
- if appstate
1003
- . find_connection ( tunnel. id , ConnectionType :: Tunnel )
1004
- . await
1005
- . is_some ( )
1006
- {
1007
- debug ! (
1008
- "Tunnel {} has already a connected state, skipping synchronization" ,
1009
- tunnel. name
1010
- ) ;
1011
- continue ;
1012
- }
1013
-
1014
- appstate
1015
- . add_connection ( tunnel. id , & interface_name, ConnectionType :: Tunnel )
1016
- . await ;
1017
-
1018
- debug ! ( "Sending event informing the frontend that a new connection has been created." ) ;
1019
- app_handle. emit_all (
1020
- CONNECTION_CHANGED ,
1021
- Payload {
1022
- message : "Created new connection" . into ( ) ,
1023
- } ,
1024
- ) ?;
1025
- debug ! ( "Event informing the frontend that a new connection has been created sent." ) ;
1026
-
1027
- //spawn log watcher
1028
- debug ! ( "Spawning log watcher for tunnel {}" , tunnel. name) ;
1029
- spawn_log_watcher_task (
1030
- app_handle. clone ( ) ,
966
+ check_connection (
967
+ & service_manager,
1031
968
tunnel. id ,
1032
- interface_name ,
969
+ & tunnel . name ,
1033
970
ConnectionType :: Tunnel ,
1034
- Level :: DEBUG ,
1035
- None ,
971
+ app_handle. clone ( ) ,
1036
972
)
1037
973
. await ?;
1038
- debug ! ( "Log watcher for tunnel {} spawned" , tunnel. name) ;
1039
974
}
1040
975
1041
976
debug ! ( "Active connections synchronized with the system state" ) ;
0 commit comments