@@ -34,6 +34,51 @@ type address =
34
34
35
35
(* console is listening on a Unix domain socket *)
36
36
37
+ (* This module enforces connection limits for VM consoles.
38
+ Depending on configuration, only one active connection per VM (including Dom0) is allowed,
39
+ or that connections are unlimited. *)
40
+ module Connection_limit = struct
41
+ module VMSet = Set. Make (String )
42
+
43
+ let active_connections : VMSet.t ref = ref VMSet. empty
44
+
45
+ let mutex = Mutex. create ()
46
+
47
+ let add vm_id =
48
+ Mutex. lock mutex ;
49
+ active_connections := VMSet. add vm_id ! active_connections ;
50
+ Mutex. unlock mutex
51
+
52
+ let remove vm_id =
53
+ Mutex. lock mutex ;
54
+ active_connections := VMSet. remove vm_id ! active_connections ;
55
+ Mutex. unlock mutex
56
+
57
+ let exists vm_id =
58
+ Mutex. lock mutex ;
59
+ let present = VMSet. mem vm_id ! active_connections in
60
+ Mutex. unlock mutex ; present
61
+
62
+ let can_add vm_id limit_console_sessions =
63
+ if not limit_console_sessions then
64
+ true
65
+ else
66
+ not (exists vm_id)
67
+ end
68
+
69
+ let connection_limit_reached __context vm_id =
70
+ let pool = Helpers. get_pool ~__context in
71
+ let limit_console_sessions =
72
+ Db.Pool. get_limit_console_sessions ~__context ~self: pool
73
+ in
74
+ if not (Connection_limit. can_add vm_id limit_console_sessions) then (
75
+ debug
76
+ " Console session limit reached: only one active session allowed for VM %s"
77
+ vm_id ;
78
+ true
79
+ ) else
80
+ false
81
+
37
82
let string_of_address = function
38
83
| Port x ->
39
84
" localhost:" ^ string_of_int x
@@ -84,26 +129,43 @@ let address_of_console __context console : address option =
84
129
) ;
85
130
address_option
86
131
87
- let real_proxy __context _ _ vnc_port s =
132
+ let real_proxy __context console _ _ vnc_port s =
88
133
try
89
- Http_svr. headers s (Http. http_200_ok () ) ;
90
- let vnc_sock =
91
- match vnc_port with
92
- | Port x ->
93
- Unixext. open_connection_fd " 127.0.0.1" x
94
- | Path x ->
95
- Unixext. open_connection_unix_fd x
96
- in
97
- (* Unixext.proxy closes fds itself so we must dup here *)
98
- let s' = Unix. dup s in
99
- debug " Connected; running proxy (between fds: %d and %d)"
100
- (Unixext. int_of_file_descr vnc_sock)
101
- (Unixext. int_of_file_descr s') ;
102
- Unixext. proxy vnc_sock s' ;
103
- debug " Proxy exited"
134
+ let vm = Db.Console. get_VM ~__context ~self: console in
135
+ let vm_id = Ref. string_of vm in
136
+ if connection_limit_reached __context vm_id then
137
+ Http_svr. headers s (Http. http_503_service_unavailable () )
138
+ else (
139
+ Http_svr. headers s (Http. http_200_ok () ) ;
140
+ let vnc_sock =
141
+ match vnc_port with
142
+ | Port x ->
143
+ Unixext. open_connection_fd " 127.0.0.1" x
144
+ | Path x ->
145
+ Unixext. open_connection_unix_fd x
146
+ in
147
+ (* Unixext.proxy closes fds itself so we must dup here *)
148
+ let s' = Unix. dup s in
149
+ debug " Connected; running proxy (between fds: %d and %d)"
150
+ (Unixext. int_of_file_descr vnc_sock)
151
+ (Unixext. int_of_file_descr s') ;
152
+ Connection_limit. add vm_id ;
153
+ Unixext. proxy vnc_sock s' ;
154
+ Connection_limit. remove vm_id ;
155
+ debug " Proxy exited"
156
+ )
104
157
with exn -> debug " error: %s" (ExnHelper. string_of_exn exn )
105
158
106
- let ws_proxy __context req protocol address s =
159
+ let ws_proxy __context _ req protocol address s =
160
+ let pool = Helpers. get_pool ~__context in
161
+ let limit_console_sessions =
162
+ Db.Pool. get_limit_console_sessions ~__context ~self: pool
163
+ in
164
+ (* Disable connection via websocket if the limit is set *)
165
+ if limit_console_sessions = true then (
166
+ Http_svr. headers s (Http. http_503_service_unavailable () ) ;
167
+ ()
168
+ ) ;
107
169
let addr = match address with Port p -> string_of_int p | Path p -> p in
108
170
let protocol =
109
171
match protocol with `rfb -> " rfb" | `vt100 -> " vt100" | `rdp -> " rdp"
@@ -247,7 +309,7 @@ let handler proxy_fn (req : Request.t) s _ =
247
309
check_vm_is_running_here __context console ;
248
310
match address_of_console __context console with
249
311
| Some vnc_port ->
250
- proxy_fn __context req protocol vnc_port s
312
+ proxy_fn __context console req protocol vnc_port s
251
313
| None ->
252
314
Http_svr. headers s (Http. http_404_missing () )
253
315
)
0 commit comments