~ubuntu-branches/debian/jessie/banshee-community-extensions/jessie

« back to all changes in this revision

Viewing changes to .pc/0001-Use-DBus-instead-of-NDesk.DBus.patch/src/Telepathy/Banshee.Telepathy/NDesk.DBus/Connection.cs

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-09-20 18:45:46 UTC
  • mfrom: (1.2.9 upstream) (5.1.8 experimental)
  • Revision ID: package-import@ubuntu.com-20110920184546-3ahue2qplydc4t0e
Tags: 2.2.0-1
* [4940fab] Imported Upstream version 2.2.0
  + Notable bug fixes:
    - Karaoke: Fix crash when switching to Now Playing
    - Lyrics: Fix crash when switching to Now Playing

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2006 Alp Toker <alp@atoker.com>
2
 
// This software is made available under the MIT License
3
 
// See COPYING for details
4
 
 
5
 
using System;
6
 
using System.Collections.Generic;
7
 
using System.IO;
8
 
using System.Threading;
9
 
using System.Reflection;
10
 
 
11
 
namespace NDesk.DBus
12
 
{
13
 
        using Authentication;
14
 
        using Transports;
15
 
 
16
 
        public partial class Connection
17
 
        {
18
 
                Transport transport;
19
 
                internal Transport Transport {
20
 
                        get {
21
 
                                return transport;
22
 
                        } set {
23
 
                                transport = value;
24
 
                                transport.Connection = this;
25
 
                        }
26
 
                }
27
 
 
28
 
                protected Connection () {}
29
 
 
30
 
                internal Connection (Transport transport)
31
 
                {
32
 
                        this.transport = transport;
33
 
                        transport.Connection = this;
34
 
                }
35
 
 
36
 
                //should this be public?
37
 
                internal Connection (string address)
38
 
                {
39
 
                        OpenPrivate (address);
40
 
                        Authenticate ();
41
 
                }
42
 
 
43
 
                internal bool isConnected = false;
44
 
                public bool IsConnected
45
 
                {
46
 
                        get {
47
 
                                return isConnected;
48
 
                        }
49
 
                }
50
 
 
51
 
                // TODO: Complete disconnection support
52
 
                internal bool isShared = false;
53
 
                public void Close ()
54
 
                {
55
 
                        if (isShared)
56
 
                                throw new Exception ("Cannot disconnect a shared Connection");
57
 
                        
58
 
                        if (!IsConnected)
59
 
                                return;
60
 
 
61
 
                        transport.Disconnect ();
62
 
                        isConnected = false;
63
 
                }
64
 
 
65
 
                //should we do connection sharing here?
66
 
                public static Connection Open (string address)
67
 
                {
68
 
                        Connection conn = new Connection ();
69
 
                        conn.OpenPrivate (address);
70
 
                        conn.Authenticate ();
71
 
 
72
 
                        return conn;
73
 
                }
74
 
 
75
 
                internal void OpenPrivate (string address)
76
 
                {
77
 
                        if (address == null)
78
 
                                throw new ArgumentNullException ("address");
79
 
 
80
 
                        AddressEntry[] entries = Address.Parse (address);
81
 
                        if (entries.Length == 0)
82
 
                                throw new Exception ("No addresses were found");
83
 
 
84
 
                        //TODO: try alternative addresses if needed
85
 
                        AddressEntry entry = entries[0];
86
 
 
87
 
                        Id = entry.GUID;
88
 
                        Transport = Transport.Create (entry);
89
 
                        isConnected = true;
90
 
                }
91
 
 
92
 
                internal UUID Id = UUID.Zero;
93
 
 
94
 
                void Authenticate ()
95
 
                {
96
 
                        if (transport != null)
97
 
                                transport.WriteCred ();
98
 
 
99
 
                        SaslClient auth = new SaslClient ();
100
 
                        auth.Identity = transport.AuthString ();
101
 
                        auth.stream = transport.Stream;
102
 
                        auth.Peer = new SaslPeer ();
103
 
                        auth.Peer.Peer = auth;
104
 
                        auth.Peer.stream = transport.Stream;
105
 
 
106
 
                        if (!auth.Authenticate ())
107
 
                                throw new Exception ("Authentication failure");
108
 
 
109
 
                        if (Id != UUID.Zero)
110
 
                                if (auth.ActualId != Id)
111
 
                                        throw new Exception ("Authentication failure: Unexpected GUID");
112
 
 
113
 
                        if (Id == UUID.Zero)
114
 
                                Id = auth.ActualId;
115
 
 
116
 
                        isAuthenticated = true;
117
 
 
118
 
                        //(((SocketTransport)Transport).socket).Blocking = false;
119
 
                }
120
 
 
121
 
                internal bool isAuthenticated = false;
122
 
                internal bool IsAuthenticated
123
 
                {
124
 
                        get {
125
 
                                return isAuthenticated;
126
 
                        }
127
 
                }
128
 
 
129
 
                //Interlocked.Increment() handles the overflow condition for uint correctly, so it's ok to store the value as an int but cast it to uint
130
 
                int serial = 0;
131
 
                internal uint GenerateSerial ()
132
 
                {
133
 
                        //return ++serial;
134
 
                        return (uint)Interlocked.Increment (ref serial);
135
 
                }
136
 
 
137
 
                internal Message SendWithReplyAndBlock (Message msg)
138
 
                {
139
 
                        PendingCall pending = SendWithReply (msg);
140
 
                        return pending.Reply;
141
 
                }
142
 
 
143
 
                internal PendingCall SendWithReply (Message msg)
144
 
                {
145
 
                        msg.ReplyExpected = true;
146
 
 
147
 
                        if (msg.Header.Serial == 0)
148
 
                                msg.Header.Serial = GenerateSerial ();
149
 
 
150
 
                        // Should we throttle the maximum number of concurrent PendingCalls?
151
 
                        // Should we support timeouts?
152
 
                        PendingCall pending = new PendingCall (this);
153
 
                        pendingCalls[msg.Header.Serial] = pending;
154
 
 
155
 
                        Send (msg);
156
 
                        //WriteMessage (msg);
157
 
 
158
 
                        return pending;
159
 
                }
160
 
 
161
 
                internal virtual uint Send (Message msg)
162
 
                {
163
 
                        if (msg.Header.Serial == 0)
164
 
                                msg.Header.Serial = GenerateSerial ();
165
 
 
166
 
                        transport.WriteMessage (msg);
167
 
 
168
 
                        //Outbound.Enqueue (msg);
169
 
                        //temporary
170
 
                        //Flush ();
171
 
 
172
 
                        return msg.Header.Serial;
173
 
                }
174
 
 
175
 
                Queue<Message> Inbound = new Queue<Message> ();
176
 
                /*
177
 
                Queue<Message> Outbound = new Queue<Message> ();
178
 
 
179
 
                public void Flush ()
180
 
                {
181
 
                        //should just iterate the enumerator here
182
 
                        while (Outbound.Count != 0) {
183
 
                                Message msg = Outbound.Dequeue ();
184
 
                                WriteMessage (msg);
185
 
                        }
186
 
                }
187
 
 
188
 
                public bool ReadWrite (int timeout_milliseconds)
189
 
                {
190
 
                        //TODO
191
 
 
192
 
                        return true;
193
 
                }
194
 
 
195
 
                public bool ReadWrite ()
196
 
                {
197
 
                        return ReadWrite (-1);
198
 
                }
199
 
 
200
 
                public bool Dispatch ()
201
 
                {
202
 
                        //TODO
203
 
                        Message msg = Inbound.Dequeue ();
204
 
                        //HandleMessage (msg);
205
 
 
206
 
                        return true;
207
 
                }
208
 
 
209
 
                public bool ReadWriteDispatch (int timeout_milliseconds)
210
 
                {
211
 
                        //TODO
212
 
                        return Dispatch ();
213
 
                }
214
 
 
215
 
                public bool ReadWriteDispatch ()
216
 
                {
217
 
                        return ReadWriteDispatch (-1);
218
 
                }
219
 
                */
220
 
 
221
 
                //temporary hack
222
 
                internal void DispatchSignals ()
223
 
                {
224
 
                        lock (Inbound) {
225
 
                                while (Inbound.Count != 0) {
226
 
                                        Message msg = Inbound.Dequeue ();
227
 
                                        HandleSignal (msg);
228
 
                                }
229
 
                        }
230
 
                }
231
 
 
232
 
                internal Thread mainThread = Thread.CurrentThread;
233
 
 
234
 
                //temporary hack
235
 
                public void Iterate ()
236
 
                {
237
 
                        mainThread = Thread.CurrentThread;
238
 
 
239
 
                        //Message msg = Inbound.Dequeue ();
240
 
                        Message msg = transport.ReadMessage ();
241
 
                        //if (msg != null)
242
 
                        HandleMessage (msg);
243
 
                        DispatchSignals ();
244
 
                }
245
 
 
246
 
                internal void Dispatch ()
247
 
                {
248
 
                        while (transport.Inbound.Count != 0) {
249
 
                                Message msg = transport.Inbound.Dequeue ();
250
 
                                HandleMessage (msg);
251
 
                        }
252
 
                        DispatchSignals ();
253
 
                }
254
 
 
255
 
                internal virtual void HandleMessage (Message msg)
256
 
                {
257
 
                        if (msg == null)
258
 
                                return;
259
 
 
260
 
                        //TODO: support disconnection situations properly and move this check elsewhere
261
 
                        if (msg == null)
262
 
                                throw new ArgumentNullException ("msg", "Cannot handle a null message; maybe the bus was disconnected");
263
 
 
264
 
                        //TODO: Restrict messages to Local ObjectPath?
265
 
 
266
 
                        {
267
 
                                object field_value = msg.Header[FieldCode.ReplySerial];
268
 
                                if (field_value != null) {
269
 
                                        uint reply_serial = (uint)field_value;
270
 
                                        PendingCall pending;
271
 
 
272
 
                                        if (pendingCalls.TryGetValue (reply_serial, out pending)) {
273
 
                                                if (pendingCalls.Remove (reply_serial))
274
 
                                                        pending.Reply = msg;
275
 
 
276
 
                                                return;
277
 
                                        }
278
 
 
279
 
                                        //we discard reply messages with no corresponding PendingCall
280
 
                                        if (Protocol.Verbose)
281
 
                                                Console.Error.WriteLine ("Unexpected reply message received: MessageType='" + msg.Header.MessageType + "', ReplySerial=" + reply_serial);
282
 
 
283
 
                                        return;
284
 
                                }
285
 
                        }
286
 
 
287
 
                        switch (msg.Header.MessageType) {
288
 
                                case MessageType.MethodCall:
289
 
                                        MethodCall method_call = new MethodCall (msg);
290
 
                                        HandleMethodCall (method_call);
291
 
                                        break;
292
 
                                case MessageType.Signal:
293
 
                                        //HandleSignal (msg);
294
 
                                        lock (Inbound)
295
 
                                                Inbound.Enqueue (msg);
296
 
                                        break;
297
 
                                case MessageType.Error:
298
 
                                        //TODO: better exception handling
299
 
                                        Error error = new Error (msg);
300
 
                                        string errMsg = String.Empty;
301
 
                                        if (msg.Signature.Value.StartsWith ("s")) {
302
 
                                                MessageReader reader = new MessageReader (msg);
303
 
                                                errMsg = reader.ReadString ();
304
 
                                        }
305
 
                                        //throw new Exception ("Remote Error: Signature='" + msg.Signature.Value + "' " + error.ErrorName + ": " + errMsg);
306
 
                                        //if (Protocol.Verbose)
307
 
                                        Console.Error.WriteLine ("Remote Error: Signature='" + msg.Signature.Value + "' " + error.ErrorName + ": " + errMsg);
308
 
                                        break;
309
 
                                case MessageType.Invalid:
310
 
                                default:
311
 
                                        throw new Exception ("Invalid message received: MessageType='" + msg.Header.MessageType + "'");
312
 
                        }
313
 
                }
314
 
 
315
 
                Dictionary<uint,PendingCall> pendingCalls = new Dictionary<uint,PendingCall> ();
316
 
 
317
 
                //this might need reworking with MulticastDelegate
318
 
                internal void HandleSignal (Message msg)
319
 
                {
320
 
                        Signal signal = new Signal (msg);
321
 
 
322
 
                        //TODO: this is a hack, not necessary when MatchRule is complete
323
 
                        MatchRule rule = new MatchRule ();
324
 
                        rule.MessageType = MessageType.Signal;
325
 
                        rule.Fields.Add (FieldCode.Interface, new MatchTest (signal.Interface));
326
 
                        rule.Fields.Add (FieldCode.Member, new MatchTest (signal.Member));
327
 
                        rule.Fields.Add (FieldCode.Path, new MatchTest (signal.Path));
328
 
 
329
 
                        Delegate dlg;
330
 
                        if (Handlers.TryGetValue (rule, out dlg)) {
331
 
                                MethodInfo mi = dlg.GetType ().GetMethod ("Invoke");
332
 
 
333
 
                                bool compatible = false;
334
 
                                Signature inSig, outSig;
335
 
 
336
 
                                if (TypeImplementer.SigsForMethod(mi, out inSig, out outSig))
337
 
                                        if (outSig == Signature.Empty && inSig == msg.Signature)
338
 
                                                compatible = true;
339
 
 
340
 
                                if (!compatible) {
341
 
                                        if (Protocol.Verbose)
342
 
                                                Console.Error.WriteLine ("Signal argument mismatch: " + signal.Interface + '.' + signal.Member);
343
 
                                        return;
344
 
                                }
345
 
 
346
 
                                //signals have no return value
347
 
                                dlg.DynamicInvoke (MessageHelper.GetDynamicValues (msg, mi.GetParameters ()));
348
 
                        } else {
349
 
                                //TODO: how should we handle this condition? sending an Error may not be appropriate in this case
350
 
                                if (Protocol.Verbose)
351
 
                                        Console.Error.WriteLine ("Warning: No signal handler for " + signal.Member);
352
 
                        }
353
 
                }
354
 
 
355
 
                internal Dictionary<MatchRule,Delegate> Handlers = new Dictionary<MatchRule,Delegate> ();
356
 
 
357
 
                //very messy
358
 
                internal void MaybeSendUnknownMethodError (MethodCall method_call)
359
 
                {
360
 
                        Message msg = MessageHelper.CreateUnknownMethodError (method_call);
361
 
                        if (msg != null)
362
 
                                Send (msg);
363
 
                }
364
 
 
365
 
                //not particularly efficient and needs to be generalized
366
 
                internal void HandleMethodCall (MethodCall method_call)
367
 
                {
368
 
                        //TODO: Ping and Introspect need to be abstracted and moved somewhere more appropriate once message filter infrastructure is complete
369
 
 
370
 
                        //FIXME: these special cases are slightly broken for the case where the member but not the interface is specified in the message
371
 
                        if (method_call.Interface == "org.freedesktop.DBus.Peer") {
372
 
                                switch (method_call.Member) {
373
 
                                        case "Ping":
374
 
                                                Send (MessageHelper.ConstructReply (method_call));
375
 
                                                return;
376
 
                                        case "GetMachineId":
377
 
                                                if (MachineId != UUID.Zero) {
378
 
                                                        Send (MessageHelper.ConstructReply (method_call, MachineId.ToString ()));
379
 
                                                        return;
380
 
                                                } else {
381
 
                                                        // Might want to send back an error here?
382
 
                                                }
383
 
                                                break;
384
 
                                }
385
 
                        }
386
 
 
387
 
                        if (method_call.Interface == "org.freedesktop.DBus.Introspectable" && method_call.Member == "Introspect") {
388
 
                                Introspector intro = new Introspector ();
389
 
                                intro.root_path = method_call.Path;
390
 
                                intro.WriteStart ();
391
 
 
392
 
                                //FIXME: do this properly
393
 
                                //this is messy and inefficient
394
 
                                List<string> linkNodes = new List<string> ();
395
 
                                int depth = method_call.Path.Decomposed.Length;
396
 
                                foreach (ObjectPath pth in RegisteredObjects.Keys) {
397
 
                                        if (pth.Value == (method_call.Path.Value)) {
398
 
                                                ExportObject exo = (ExportObject)RegisteredObjects[pth];
399
 
                                                exo.WriteIntrospect (intro);
400
 
                                        } else {
401
 
                                                for (ObjectPath cur = pth ; cur != null ; cur = cur.Parent) {
402
 
                                                        if (cur.Value == method_call.Path.Value) {
403
 
                                                                string linkNode = pth.Decomposed[depth];
404
 
                                                                if (!linkNodes.Contains (linkNode)) {
405
 
                                                                        intro.WriteNode (linkNode);
406
 
                                                                        linkNodes.Add (linkNode);
407
 
                                                                }
408
 
                                                        }
409
 
                                                }
410
 
                                        }
411
 
                                }
412
 
 
413
 
                                intro.WriteEnd ();
414
 
 
415
 
                                Message reply = MessageHelper.ConstructReply (method_call, intro.xml);
416
 
                                Send (reply);
417
 
                                return;
418
 
                        }
419
 
 
420
 
                        BusObject bo;
421
 
                        if (RegisteredObjects.TryGetValue (method_call.Path, out bo)) {
422
 
                                ExportObject eo = (ExportObject)bo;
423
 
                                eo.HandleMethodCall (method_call);
424
 
                        } else {
425
 
                                MaybeSendUnknownMethodError (method_call);
426
 
                        }
427
 
                }
428
 
 
429
 
                Dictionary<ObjectPath,BusObject> RegisteredObjects = new Dictionary<ObjectPath,BusObject> ();
430
 
 
431
 
                //FIXME: this shouldn't be part of the core API
432
 
                //that also applies to much of the other object mapping code
433
 
 
434
 
                public object GetObject (Type type, string bus_name, ObjectPath path)
435
 
                {
436
 
                        //if (type == null)
437
 
                        //      return GetObject (bus_name, path);
438
 
 
439
 
                        //if the requested type is an interface, we can implement it efficiently
440
 
                        //otherwise we fall back to using a transparent proxy
441
 
                        if (type.IsInterface || type.IsAbstract) {
442
 
                                return BusObject.GetObject (this, bus_name, path, type);
443
 
                        } else {
444
 
                                if (Protocol.Verbose)
445
 
                                        Console.Error.WriteLine ("Warning: Note that MarshalByRefObject use is not recommended; for best performance, define interfaces");
446
 
 
447
 
                                BusObject busObject = new BusObject (this, bus_name, path);
448
 
                                DProxy prox = new DProxy (busObject, type);
449
 
                                return prox.GetTransparentProxy ();
450
 
                        }
451
 
                }
452
 
 
453
 
                public T GetObject<T> (string bus_name, ObjectPath path)
454
 
                {
455
 
                        return (T)GetObject (typeof (T), bus_name, path);
456
 
                }
457
 
 
458
 
                [Obsolete ("Use the overload of Register() which does not take a bus_name parameter")]
459
 
                public void Register (string bus_name, ObjectPath path, object obj)
460
 
                {
461
 
                        Register (path, obj);
462
 
                }
463
 
 
464
 
                [Obsolete ("Use the overload of Unregister() which does not take a bus_name parameter")]
465
 
                public object Unregister (string bus_name, ObjectPath path)
466
 
                {
467
 
                        return Unregister (path);
468
 
                }
469
 
 
470
 
                public void Register (ObjectPath path, object obj)
471
 
                {
472
 
                        ExportObject eo = ExportObject.CreateExportObject (this, path, obj);
473
 
                        eo.Registered = true;
474
 
 
475
 
                        //TODO: implement some kind of tree data structure or internal object hierarchy. right now we are ignoring the name and putting all object paths in one namespace, which is bad
476
 
                        RegisteredObjects[path] = eo;
477
 
                }
478
 
 
479
 
                public object Unregister (ObjectPath path)
480
 
                {
481
 
                        BusObject bo;
482
 
 
483
 
                        if (!RegisteredObjects.TryGetValue (path, out bo))
484
 
                                throw new Exception ("Cannot unregister " + path + " as it isn't registered");
485
 
 
486
 
                        RegisteredObjects.Remove (path);
487
 
 
488
 
                        ExportObject eo = (ExportObject)bo;
489
 
                        eo.Registered = false;
490
 
 
491
 
                        return eo.obj;
492
 
                }
493
 
 
494
 
                //these look out of place, but are useful
495
 
                internal protected virtual void AddMatch (string rule)
496
 
                {
497
 
                }
498
 
 
499
 
                internal protected virtual void RemoveMatch (string rule)
500
 
                {
501
 
                }
502
 
 
503
 
                // Maybe we should use XDG/basedir or check an env var for this?
504
 
                const string machineUuidFilename = @"/var/lib/dbus/machine-id";
505
 
                static UUID? machineId = null;
506
 
                private static object idReadLock = new object ();
507
 
                internal static UUID MachineId
508
 
                {
509
 
                        get {
510
 
                                lock (idReadLock) {
511
 
                                        if (machineId != null)
512
 
                                                return (UUID)machineId;
513
 
                                        try {
514
 
                                                machineId = ReadMachineId (machineUuidFilename);
515
 
                                        } catch {
516
 
                                                machineId = UUID.Zero;
517
 
                                        }
518
 
                                        return (UUID)machineId;
519
 
                                }
520
 
                        }
521
 
                }
522
 
 
523
 
                static UUID ReadMachineId (string fname)
524
 
                {
525
 
                        using (FileStream fs = File.OpenRead (fname)) {
526
 
                                // Length is typically 33 (32 for the UUID, plus a linefeed)
527
 
                                //if (fs.Length < 32)
528
 
                                //      return UUID.Zero;
529
 
 
530
 
                                byte[] data = new byte[32];
531
 
 
532
 
                                int pos = 0;
533
 
                                while (pos < data.Length) {
534
 
                                        int read = fs.Read (data, pos, data.Length - pos);
535
 
                                        if (read == 0)
536
 
                                                break;
537
 
                                        pos += read;
538
 
                                }
539
 
 
540
 
                                if (pos != data.Length)
541
 
                                        //return UUID.Zero;
542
 
                                        throw new Exception ("Insufficient data while reading GUID string");
543
 
 
544
 
                                return UUID.Parse (System.Text.Encoding.ASCII.GetString (data));
545
 
                        }
546
 
                }
547
 
 
548
 
 
549
 
                /*
550
 
                [DllImport ("advapi32.dll", SetLastError = true)]
551
 
                static extern bool GetCurrentHwProfile (IntPtr fProfile);
552
 
 
553
 
                [StructLayout (LayoutKind.Sequential)]
554
 
                private class HWProfile
555
 
                {
556
 
                        public Int32 dwDockInfo;
557
 
                        [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 39)]
558
 
                        public string szHwProfileGuid;
559
 
                        [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 80)]
560
 
                        public string szHwProfileName;
561
 
                }
562
 
 
563
 
                static UUID ReadMachineIdWin32 ()
564
 
                {
565
 
                        // Completely untested
566
 
                        string lText = null;
567
 
 
568
 
                        IntPtr lHWInfoPtr = Marshal.AllocHGlobal (123);
569
 
                        HWProfile lProfile = new HWProfile ();
570
 
                        Marshal.StructureToPtr (lProfile, lHWInfoPtr, false);
571
 
                        if (GetCurrentHwProfile (lHWInfoPtr)) {
572
 
                                Marshal.PtrToStructure (lHWInfoPtr, lProfile);
573
 
                                lText = lProfile.szHwProfileGuid.ToString ();
574
 
                        }
575
 
                        Marshal.FreeHGlobal (lHWInfoPtr);
576
 
 
577
 
                        string uuidString = lText.Replace ("-", String.Empty).Substring (1, 32);
578
 
                        return UUID.Parse (uuidString);
579
 
                }
580
 
                */
581
 
 
582
 
                static Connection ()
583
 
                {
584
 
                        if (BitConverter.IsLittleEndian)
585
 
                                NativeEndianness = EndianFlag.Little;
586
 
                        else
587
 
                                NativeEndianness = EndianFlag.Big;
588
 
                }
589
 
 
590
 
                internal static readonly EndianFlag NativeEndianness;
591
 
        }
592
 
}