1414// limitations under the License.
1515//
1616
17- #import " UTMQemuManager.h"
17+ #import " UTMQemuManager-Protected .h"
1818#import " UTMJSONStream.h"
1919#import " UTMLogging.h"
20- #import " qapi-commands.h"
2120#import " qapi-emit-events.h"
22- #import " qapi-events.h"
23- #import " error.h"
2421
2522extern NSString *const kUTMErrorDomain ;
2623const int64_t kRPCTimeout = (int64_t )10 *NSEC_PER_SEC;
2724
28- static void utm_shutdown_handler (bool guest, ShutdownCause reason, void *ctx) {
29- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
30- [self .delegate qemuWillQuit: self guest: guest reason: reason];
31- }
32-
33- static void utm_powerdown_handler (void *ctx) {
34-
35- }
36-
37- static void utm_reset_handler (bool guest, ShutdownCause reason, void *ctx) {
38- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
39- [self .delegate qemuHasReset: self guest: guest reason: reason];
40- }
41-
42- static void utm_stop_handler (void *ctx) {
43- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
44- [self .delegate qemuHasStopped: self ];
45- }
46-
47- static void utm_resume_handler (void *ctx) {
48- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
49- [self .delegate qemuHasResumed: self ];
50- }
51-
52- static void utm_suspend_handler (void *ctx) {
53- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
54- [self .delegate qemuHasSuspended: self ];
55- }
56-
57- static void utm_suspend_disk_handler (void *ctx) {
58-
59- }
60-
61- static void utm_wakeup_handler (void *ctx) {
62- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
63- [self .delegate qemuHasWakeup: self ];
64- }
65-
66- static void utm_watchdog_handler (WatchdogAction action, void *ctx) {
67-
68- }
69-
70- static void utm_guest_panicked_handler (GuestPanicAction action, bool has_info, GuestPanicInformation *info, void *ctx) {
71- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
72- [self .delegate qemuError: self error: NSLocalizedString(@" Guest panic" , @" UTMQemuManager" )];
73- }
74-
75- static void utm_block_image_corrupted_handler (const char *device, bool has_node_name, const char *node_name, const char *msg, bool has_offset, int64_t offset, bool has_size, int64_t size, bool fatal, void *ctx) {
76- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
77- if (fatal) {
78- [self .delegate qemuError: self error: [NSString stringWithFormat: @" %s , %s : %s " , device, node_name, msg]];
79- }
80- }
81-
82- static void utm_block_io_error_handler (const char *device, bool has_node_name, const char *node_name, IoOperationType operation, BlockErrorAction action, bool has_nospace, bool nospace, const char *reason, void *ctx) {
83- UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
84- [self .delegate qemuError: self error: [NSString stringWithFormat: @" %s , %s : %s " , device, node_name, reason]];
85- }
86-
87- static void utm_spice_connected_handler (SpiceBasicInfo *server, SpiceBasicInfo *client, void *ctx) {
88-
89- }
90-
91- static void utm_spice_initialized_handler (SpiceServerInfo *server, SpiceChannel *client, void *ctx) {
92-
93- }
94-
95- static void utm_spice_disconnected_handler (SpiceBasicInfo *server, SpiceBasicInfo *client, void *ctx) {
96-
97- }
98-
99- static void utm_spice_migrate_completed_handler (void *ctx) {
100-
101- }
102-
103- static void utm_migration_handler (MigrationStatus status, void *ctx) {
104-
105- }
106-
107- static void utm_migration_pass_handler (int64_t pass, void *ctx) {
108-
109- }
110-
11125typedef void (^rpcCompletionHandler_t)(NSDictionary *, NSError *);
11226
11327@interface UTMQemuManager ()
11428
115- @property (nonatomic , readwrite ) BOOL isConnected;
11629@property (nonatomic , nullable ) rpcCompletionHandler_t rpcCallback;
11730@property (nonatomic ) UTMJSONStream *jsonStream;
11831@property (nonatomic ) dispatch_semaphore_t cmdLock;
@@ -121,6 +34,12 @@ @interface UTMQemuManager ()
12134
12235@implementation UTMQemuManager
12336
37+ @synthesize isConnected = _isConnected;
38+
39+ - (void )setIsConnected : (BOOL )isConnected {
40+ _isConnected = isConnected;
41+ }
42+
12443void qmp_rpc_call (CFDictionaryRef args, CFDictionaryRef *ret, Error **err, void *ctx) {
12544 UTMQemuManager *self = (__bridge UTMQemuManager *)ctx;
12645 dispatch_semaphore_t rpc_sema = dispatch_semaphore_create (0 );
@@ -208,9 +127,7 @@ - (void)jsonStream:(UTMJSONStream *)stream receivedDictionary:(NSDictionary *)di
208127 const char *event = [dict[@" event" ] cStringUsingEncoding: NSASCIIStringEncoding];
209128 qapi_event_dispatch (event, (__bridge CFTypeRef)dict, (__bridge void *)self);
210129 *stop = YES ;
211- } else if ([key isEqualToString: @" QMP" ]) {
212- UTMLog (@" Got QMP handshake: %@ " , dict);
213- [self .delegate qemuQmpDidConnect: self ];
130+ } else if ([self didGetUnhandledKey: key value: val]) {
214131 *stop = YES ;
215132 }
216133 }];
@@ -220,158 +137,8 @@ - (__autoreleasing NSError *)errorForQerror:(Error *)qerr {
220137 return [NSError errorWithDomain: kUTMErrorDomain code: -1 userInfo: @{NSLocalizedDescriptionKey : [NSString stringWithCString: error_get_pretty (qerr) encoding: NSASCIIStringEncoding]}];
221138}
222139
223- - (BOOL )qmpEnterCommandModeWithError : (NSError * _Nullable __autoreleasing *)error {
224- NSDictionary *cmd = @{
225- @" execute" : @" qmp_capabilities"
226- };
227- Error *qerr = NULL ;
228- qmp_rpc_call ((__bridge CFDictionaryRef)cmd, NULL , &qerr, (__bridge void *)self);
229- if (qerr != NULL ) {
230- if (error) {
231- *error = [self errorForQerror: qerr];
232- error_free (qerr);
233- }
234- return NO ;
235- } else {
236- self.isConnected = YES ;
237- return YES ;
238- }
239- }
240-
241- - (BOOL )continueBootWithError : (NSError * _Nullable __autoreleasing *)error {
242- Error *qerr = NULL ;
243- qmp_cont (&qerr, (__bridge void *)self);
244- if (qerr != NULL ) {
245- if (error) {
246- *error = [self errorForQerror: qerr];
247- error_free (qerr);
248- }
249- self.isConnected = NO ;
250- return NO ;
251- } else {
252- return YES ;
253- }
254- }
255-
256- - (void )qmpPowerCommand : (NSString *)command completion : (void (^ _Nullable)(NSError * _Nullable))completion {
257- dispatch_async (dispatch_get_global_queue (QOS_CLASS_UTILITY, 0 ), ^{
258- Error *qerr = NULL ;
259- NSError *err;
260- NSDictionary *cmd = @{
261- @" execute" : command
262- };
263- qmp_rpc_call ((__bridge CFDictionaryRef)cmd, NULL , &qerr, (__bridge void *)self);
264- if (qerr) {
265- err = [self errorForQerror: qerr];
266- error_free (qerr);
267- }
268- if (completion) {
269- completion (err);
270- }
271- });
272- }
273-
274- - (void )qmpHmpCommand : (NSString *)cmd completion : (void (^)(NSString * _Nullable, NSError * _Nullable))completion {
275- dispatch_async (dispatch_get_global_queue (QOS_CLASS_UTILITY, 0 ), ^{
276- Error *qerr = NULL ;
277- NSError *err;
278- NSString *result;
279- char *res;
280- res = qmp_human_monitor_command ([cmd cStringUsingEncoding: NSASCIIStringEncoding], false , 0 , &qerr, (__bridge void *)self);
281- if (res) {
282- result = [NSString stringWithCString: res encoding: NSASCIIStringEncoding];
283- g_free (res);
284- }
285- if (qerr) {
286- err = [self errorForQerror: qerr];
287- error_free (qerr);
288- }
289- if (completion) {
290- completion (result, err);
291- }
292- });
293- }
294-
295- - (void )qemuPowerDownWithCompletion : (void (^ _Nullable)(NSError * _Nullable))completion {
296- [self qmpPowerCommand: @" system_powerdown" completion: completion];
297- }
298-
299- - (void )qemuResetWithCompletion : (void (^ _Nullable)(NSError * _Nullable))completion {
300- [self qmpPowerCommand: @" system_reset" completion: completion];
301- }
302-
303- - (void )qemuStopWithCompletion : (void (^ _Nullable)(NSError * _Nullable))completion {
304- [self qmpPowerCommand: @" stop" completion: completion];
305- }
306-
307- - (void )qemuResumeWithCompletion : (void (^ _Nullable)(NSError * _Nullable))completion {
308- [self qmpPowerCommand: @" cont" completion: completion];
309- }
310-
311- - (void )qemuQuitWithCompletion : (void (^ _Nullable)(NSError * _Nullable))completion {
312- [self qmpPowerCommand: @" quit" completion: completion];
313- }
314-
315- - (void )qemuSaveStateWithCompletion : (void (^)(NSString * _Nullable, NSError * _Nullable))completion snapshotName : (NSString *)name {
316- NSString *cmd = [NSString stringWithFormat: @" savevm %@ " , name];
317- [self qmpHmpCommand: cmd completion: completion];
318- }
319-
320- - (void )qemuDeleteStateWithCompletion : (void (^)(NSString * _Nullable, NSError * _Nullable))completion snapshotName : (NSString *)name {
321- NSString *cmd = [NSString stringWithFormat: @" delvm %@ " , name];
322- [self qmpHmpCommand: cmd completion: completion];
323- }
324-
325- - (void )mouseIndexForAbsolute : (BOOL )absolute withCompletion : (void (^)(int64_t , NSError * _Nullable))completion {
326- dispatch_async (dispatch_get_global_queue (QOS_CLASS_UTILITY, 0 ), ^{
327- MouseInfoList *info = NULL ;
328- Error *qerr = NULL ;
329- int64_t index = -1 ;
330- NSError *err;
331- info = qmp_query_mice (&qerr, (__bridge void *)self);
332- if (qerr) {
333- err = [self errorForQerror: qerr];
334- error_free (qerr);
335- }
336- if (info) {
337- for (MouseInfoList *list = info; list; list = list->next ) {
338- if (list->value ->absolute == absolute) {
339- index = list->value ->index ;
340- break ;
341- }
342- }
343- qapi_free_MouseInfoList (info);
344- }
345- if (completion) {
346- completion (index, err);
347- }
348- });
349- }
350-
351- - (void )mouseSelect : (int64_t )index withCompletion : (void (^)(NSString * _Nullable, NSError * _Nullable))completion {
352- NSString *cmd = [NSString stringWithFormat: @" mouse_set %lld " , index];
353- [self qmpHmpCommand: cmd completion: completion];
140+ - (BOOL )didGetUnhandledKey : (NSString *)key value : (id )value {
141+ return NO ;
354142}
355143
356144@end
357-
358- qapi_enum_handler_registry qapi_enum_handler_registry_data = {
359- .qapi_shutdown_handler = utm_shutdown_handler,
360- .qapi_powerdown_handler = utm_powerdown_handler,
361- .qapi_reset_handler = utm_reset_handler,
362- .qapi_stop_handler = utm_stop_handler,
363- .qapi_resume_handler = utm_resume_handler,
364- .qapi_suspend_handler = utm_suspend_handler,
365- .qapi_suspend_disk_handler = utm_suspend_disk_handler,
366- .qapi_wakeup_handler = utm_wakeup_handler,
367- .qapi_watchdog_handler = utm_watchdog_handler,
368- .qapi_guest_panicked_handler = utm_guest_panicked_handler,
369- .qapi_block_image_corrupted_handler = utm_block_image_corrupted_handler,
370- .qapi_block_io_error_handler = utm_block_io_error_handler,
371- .qapi_spice_connected_handler = utm_spice_connected_handler,
372- .qapi_spice_initialized_handler = utm_spice_initialized_handler,
373- .qapi_spice_disconnected_handler = utm_spice_disconnected_handler,
374- .qapi_spice_migrate_completed_handler = utm_spice_migrate_completed_handler,
375- .qapi_migration_handler = utm_migration_handler,
376- .qapi_migration_pass_handler = utm_migration_pass_handler,
377- };
0 commit comments