default_handler.go (7691B)
1 package dbus 2 3 import ( 4 "bytes" 5 "reflect" 6 "strings" 7 "sync" 8 ) 9 10 func newIntrospectIntf(h *defaultHandler) *exportedIntf { 11 methods := make(map[string]Method) 12 methods["Introspect"] = exportedMethod{ 13 reflect.ValueOf(func(msg Message) (string, *Error) { 14 path := msg.Headers[FieldPath].value.(ObjectPath) 15 return h.introspectPath(path), nil 16 }), 17 } 18 return newExportedIntf(methods, true) 19 } 20 21 //NewDefaultHandler returns an instance of the default 22 //call handler. This is useful if you want to implement only 23 //one of the two handlers but not both. 24 // 25 // Deprecated: this is the default value, don't use it, it will be unexported. 26 func NewDefaultHandler() *defaultHandler { 27 h := &defaultHandler{ 28 objects: make(map[ObjectPath]*exportedObj), 29 defaultIntf: make(map[string]*exportedIntf), 30 } 31 h.defaultIntf["org.freedesktop.DBus.Introspectable"] = newIntrospectIntf(h) 32 return h 33 } 34 35 type defaultHandler struct { 36 sync.RWMutex 37 objects map[ObjectPath]*exportedObj 38 defaultIntf map[string]*exportedIntf 39 } 40 41 func (h *defaultHandler) PathExists(path ObjectPath) bool { 42 _, ok := h.objects[path] 43 return ok 44 } 45 46 func (h *defaultHandler) introspectPath(path ObjectPath) string { 47 subpath := make(map[string]struct{}) 48 var xml bytes.Buffer 49 xml.WriteString("<node>") 50 for obj := range h.objects { 51 p := string(path) 52 if p != "/" { 53 p += "/" 54 } 55 if strings.HasPrefix(string(obj), p) { 56 node_name := strings.Split(string(obj[len(p):]), "/")[0] 57 subpath[node_name] = struct{}{} 58 } 59 } 60 for s := range subpath { 61 xml.WriteString("\n\t<node name=\"" + s + "\"/>") 62 } 63 xml.WriteString("\n</node>") 64 return xml.String() 65 } 66 67 func (h *defaultHandler) LookupObject(path ObjectPath) (ServerObject, bool) { 68 h.RLock() 69 defer h.RUnlock() 70 object, ok := h.objects[path] 71 if ok { 72 return object, ok 73 } 74 75 // If an object wasn't found for this exact path, 76 // look for a matching subtree registration 77 subtreeObject := newExportedObject() 78 path = path[:strings.LastIndex(string(path), "/")] 79 for len(path) > 0 { 80 object, ok = h.objects[path] 81 if ok { 82 for name, iface := range object.interfaces { 83 // Only include this handler if it registered for the subtree 84 if iface.isFallbackInterface() { 85 subtreeObject.interfaces[name] = iface 86 } 87 } 88 break 89 } 90 91 path = path[:strings.LastIndex(string(path), "/")] 92 } 93 94 for name, intf := range h.defaultIntf { 95 if _, exists := subtreeObject.interfaces[name]; exists { 96 continue 97 } 98 subtreeObject.interfaces[name] = intf 99 } 100 101 return subtreeObject, true 102 } 103 104 func (h *defaultHandler) AddObject(path ObjectPath, object *exportedObj) { 105 h.Lock() 106 h.objects[path] = object 107 h.Unlock() 108 } 109 110 func (h *defaultHandler) DeleteObject(path ObjectPath) { 111 h.Lock() 112 delete(h.objects, path) 113 h.Unlock() 114 } 115 116 type exportedMethod struct { 117 reflect.Value 118 } 119 120 func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) { 121 t := m.Type() 122 123 params := make([]reflect.Value, len(args)) 124 for i := 0; i < len(args); i++ { 125 params[i] = reflect.ValueOf(args[i]).Elem() 126 } 127 128 ret := m.Value.Call(params) 129 var err error 130 nilErr := false // The reflection will find almost-nils, let's only pass back clean ones! 131 if t.NumOut() > 0 { 132 if e, ok := ret[t.NumOut()-1].Interface().(*Error); ok { // godbus *Error 133 nilErr = ret[t.NumOut()-1].IsNil() 134 ret = ret[:t.NumOut()-1] 135 err = e 136 } else if ret[t.NumOut()-1].Type().Implements(errType) { // Go error 137 i := ret[t.NumOut()-1].Interface() 138 if i == nil { 139 nilErr = ret[t.NumOut()-1].IsNil() 140 } else { 141 err = i.(error) 142 } 143 ret = ret[:t.NumOut()-1] 144 } 145 } 146 out := make([]interface{}, len(ret)) 147 for i, val := range ret { 148 out[i] = val.Interface() 149 } 150 if nilErr || err == nil { 151 //concrete type to interface nil is a special case 152 return out, nil 153 } 154 return out, err 155 } 156 157 func (m exportedMethod) NumArguments() int { 158 return m.Value.Type().NumIn() 159 } 160 161 func (m exportedMethod) ArgumentValue(i int) interface{} { 162 return reflect.Zero(m.Type().In(i)).Interface() 163 } 164 165 func (m exportedMethod) NumReturns() int { 166 return m.Value.Type().NumOut() 167 } 168 169 func (m exportedMethod) ReturnValue(i int) interface{} { 170 return reflect.Zero(m.Type().Out(i)).Interface() 171 } 172 173 func newExportedObject() *exportedObj { 174 return &exportedObj{ 175 interfaces: make(map[string]*exportedIntf), 176 } 177 } 178 179 type exportedObj struct { 180 mu sync.RWMutex 181 interfaces map[string]*exportedIntf 182 } 183 184 func (obj *exportedObj) LookupInterface(name string) (Interface, bool) { 185 if name == "" { 186 return obj, true 187 } 188 obj.mu.RLock() 189 defer obj.mu.RUnlock() 190 intf, exists := obj.interfaces[name] 191 return intf, exists 192 } 193 194 func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) { 195 obj.mu.Lock() 196 defer obj.mu.Unlock() 197 obj.interfaces[name] = iface 198 } 199 200 func (obj *exportedObj) DeleteInterface(name string) { 201 obj.mu.Lock() 202 defer obj.mu.Unlock() 203 delete(obj.interfaces, name) 204 } 205 206 func (obj *exportedObj) LookupMethod(name string) (Method, bool) { 207 obj.mu.RLock() 208 defer obj.mu.RUnlock() 209 for _, intf := range obj.interfaces { 210 method, exists := intf.LookupMethod(name) 211 if exists { 212 return method, exists 213 } 214 } 215 return nil, false 216 } 217 218 func (obj *exportedObj) isFallbackInterface() bool { 219 return false 220 } 221 222 func newExportedIntf(methods map[string]Method, includeSubtree bool) *exportedIntf { 223 return &exportedIntf{ 224 methods: methods, 225 includeSubtree: includeSubtree, 226 } 227 } 228 229 type exportedIntf struct { 230 methods map[string]Method 231 232 // Whether or not this export is for the entire subtree 233 includeSubtree bool 234 } 235 236 func (obj *exportedIntf) LookupMethod(name string) (Method, bool) { 237 out, exists := obj.methods[name] 238 return out, exists 239 } 240 241 func (obj *exportedIntf) isFallbackInterface() bool { 242 return obj.includeSubtree 243 } 244 245 //NewDefaultSignalHandler returns an instance of the default 246 //signal handler. This is useful if you want to implement only 247 //one of the two handlers but not both. 248 // 249 // Deprecated: this is the default value, don't use it, it will be unexported. 250 func NewDefaultSignalHandler() *defaultSignalHandler { 251 return &defaultSignalHandler{} 252 } 253 254 type defaultSignalHandler struct { 255 mu sync.RWMutex 256 closed bool 257 signals []*signalChannelData 258 } 259 260 func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) { 261 sh.mu.RLock() 262 defer sh.mu.RUnlock() 263 if sh.closed { 264 return 265 } 266 for _, scd := range sh.signals { 267 scd.deliver(signal) 268 } 269 } 270 271 func (sh *defaultSignalHandler) Terminate() { 272 sh.mu.Lock() 273 defer sh.mu.Unlock() 274 if sh.closed { 275 return 276 } 277 278 for _, scd := range sh.signals { 279 scd.close() 280 close(scd.ch) 281 } 282 sh.closed = true 283 sh.signals = nil 284 } 285 286 func (sh *defaultSignalHandler) AddSignal(ch chan<- *Signal) { 287 sh.mu.Lock() 288 defer sh.mu.Unlock() 289 if sh.closed { 290 return 291 } 292 sh.signals = append(sh.signals, &signalChannelData{ 293 ch: ch, 294 done: make(chan struct{}), 295 }) 296 } 297 298 func (sh *defaultSignalHandler) RemoveSignal(ch chan<- *Signal) { 299 sh.mu.Lock() 300 defer sh.mu.Unlock() 301 if sh.closed { 302 return 303 } 304 for i := len(sh.signals) - 1; i >= 0; i-- { 305 if ch == sh.signals[i].ch { 306 sh.signals[i].close() 307 copy(sh.signals[i:], sh.signals[i+1:]) 308 sh.signals[len(sh.signals)-1] = nil 309 sh.signals = sh.signals[:len(sh.signals)-1] 310 } 311 } 312 } 313 314 type signalChannelData struct { 315 wg sync.WaitGroup 316 ch chan<- *Signal 317 done chan struct{} 318 } 319 320 func (scd *signalChannelData) deliver(signal *Signal) { 321 select { 322 case scd.ch <- signal: 323 case <-scd.done: 324 return 325 default: 326 scd.wg.Add(1) 327 go scd.deferredDeliver(signal) 328 } 329 } 330 331 func (scd *signalChannelData) deferredDeliver(signal *Signal) { 332 select { 333 case scd.ch <- signal: 334 case <-scd.done: 335 } 336 scd.wg.Done() 337 } 338 339 func (scd *signalChannelData) close() { 340 close(scd.done) 341 scd.wg.Wait() // wait until all spawned goroutines return 342 }