1package hcs 2 3import ( 4 "fmt" 5 "sync" 6 "syscall" 7 8 "github.com/Microsoft/hcsshim/internal/interop" 9 "github.com/Microsoft/hcsshim/internal/logfields" 10 "github.com/Microsoft/hcsshim/internal/vmcompute" 11 "github.com/sirupsen/logrus" 12) 13 14var ( 15 nextCallback uintptr 16 callbackMap = map[uintptr]*notifcationWatcherContext{} 17 callbackMapLock = sync.RWMutex{} 18 19 notificationWatcherCallback = syscall.NewCallback(notificationWatcher) 20 21 // Notifications for HCS_SYSTEM handles 22 hcsNotificationSystemExited hcsNotification = 0x00000001 23 hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002 24 hcsNotificationSystemStartCompleted hcsNotification = 0x00000003 25 hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004 26 hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005 27 hcsNotificationSystemCrashReport hcsNotification = 0x00000006 28 hcsNotificationSystemSiloJobCreated hcsNotification = 0x00000007 29 hcsNotificationSystemSaveCompleted hcsNotification = 0x00000008 30 hcsNotificationSystemRdpEnhancedModeStateChanged hcsNotification = 0x00000009 31 hcsNotificationSystemShutdownFailed hcsNotification = 0x0000000A 32 hcsNotificationSystemGetPropertiesCompleted hcsNotification = 0x0000000B 33 hcsNotificationSystemModifyCompleted hcsNotification = 0x0000000C 34 hcsNotificationSystemCrashInitiated hcsNotification = 0x0000000D 35 hcsNotificationSystemGuestConnectionClosed hcsNotification = 0x0000000E 36 37 // Notifications for HCS_PROCESS handles 38 hcsNotificationProcessExited hcsNotification = 0x00010000 39 40 // Common notifications 41 hcsNotificationInvalid hcsNotification = 0x00000000 42 hcsNotificationServiceDisconnect hcsNotification = 0x01000000 43) 44 45type hcsNotification uint32 46 47func (hn hcsNotification) String() string { 48 switch hn { 49 case hcsNotificationSystemExited: 50 return "SystemExited" 51 case hcsNotificationSystemCreateCompleted: 52 return "SystemCreateCompleted" 53 case hcsNotificationSystemStartCompleted: 54 return "SystemStartCompleted" 55 case hcsNotificationSystemPauseCompleted: 56 return "SystemPauseCompleted" 57 case hcsNotificationSystemResumeCompleted: 58 return "SystemResumeCompleted" 59 case hcsNotificationSystemCrashReport: 60 return "SystemCrashReport" 61 case hcsNotificationSystemSiloJobCreated: 62 return "SystemSiloJobCreated" 63 case hcsNotificationSystemSaveCompleted: 64 return "SystemSaveCompleted" 65 case hcsNotificationSystemRdpEnhancedModeStateChanged: 66 return "SystemRdpEnhancedModeStateChanged" 67 case hcsNotificationSystemShutdownFailed: 68 return "SystemShutdownFailed" 69 case hcsNotificationSystemGetPropertiesCompleted: 70 return "SystemGetPropertiesCompleted" 71 case hcsNotificationSystemModifyCompleted: 72 return "SystemModifyCompleted" 73 case hcsNotificationSystemCrashInitiated: 74 return "SystemCrashInitiated" 75 case hcsNotificationSystemGuestConnectionClosed: 76 return "SystemGuestConnectionClosed" 77 case hcsNotificationProcessExited: 78 return "ProcessExited" 79 case hcsNotificationInvalid: 80 return "Invalid" 81 case hcsNotificationServiceDisconnect: 82 return "ServiceDisconnect" 83 default: 84 return fmt.Sprintf("Unknown: %d", hn) 85 } 86} 87 88type notificationChannel chan error 89 90type notifcationWatcherContext struct { 91 channels notificationChannels 92 handle vmcompute.HcsCallback 93 94 systemID string 95 processID int 96} 97 98type notificationChannels map[hcsNotification]notificationChannel 99 100func newSystemChannels() notificationChannels { 101 channels := make(notificationChannels) 102 for _, notif := range []hcsNotification{ 103 hcsNotificationServiceDisconnect, 104 hcsNotificationSystemExited, 105 hcsNotificationSystemCreateCompleted, 106 hcsNotificationSystemStartCompleted, 107 hcsNotificationSystemPauseCompleted, 108 hcsNotificationSystemResumeCompleted, 109 } { 110 channels[notif] = make(notificationChannel, 1) 111 } 112 return channels 113} 114 115func newProcessChannels() notificationChannels { 116 channels := make(notificationChannels) 117 for _, notif := range []hcsNotification{ 118 hcsNotificationServiceDisconnect, 119 hcsNotificationProcessExited, 120 } { 121 channels[notif] = make(notificationChannel, 1) 122 } 123 return channels 124} 125 126func closeChannels(channels notificationChannels) { 127 for _, c := range channels { 128 close(c) 129 } 130} 131 132func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr { 133 var result error 134 if int32(notificationStatus) < 0 { 135 result = interop.Win32FromHresult(notificationStatus) 136 } 137 138 callbackMapLock.RLock() 139 context := callbackMap[callbackNumber] 140 callbackMapLock.RUnlock() 141 142 if context == nil { 143 return 0 144 } 145 146 log := logrus.WithFields(logrus.Fields{ 147 "notification-type": notificationType.String(), 148 "system-id": context.systemID, 149 }) 150 if context.processID != 0 { 151 log.Data[logfields.ProcessID] = context.processID 152 } 153 log.Debug("HCS notification") 154 155 if channel, ok := context.channels[notificationType]; ok { 156 channel <- result 157 } 158 159 return 0 160} 161