~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/maccore/src/CoreFoundation/CFStream.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
// CFStream.cs:
3
3
//
4
4
// Authors:
 
5
//              Martin Baulig <martin.baulig@gmail.com>
5
6
//              Rolf Bjarne Kvinge <rolf@xamarin.com>
6
7
//     
7
8
// Copyright (C) 2012 Xamarin, Inc.
25
26
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
27
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28
//
28
 
 
29
29
using System;
30
30
using System.Net;
 
31
using System.Net.Sockets;
31
32
using System.Runtime.InteropServices;
 
33
using MonoMac.CoreServices;
32
34
using MonoMac.ObjCRuntime;
33
35
using MonoMac.Foundation;
34
36
 
35
37
namespace MonoMac.CoreFoundation {
 
38
 
36
39
        [Flags]
37
 
        public enum CFStreamEventType
38
 
        {
 
40
        public enum CFStreamEventType {
39
41
                None = 0,
40
42
                OpenCompleted = 1,
41
43
                HasBytesAvailable = 2,
45
47
        }
46
48
        
47
49
        [StructLayout (LayoutKind.Sequential)]
48
 
        public struct CFStreamClientContext
49
 
        {
 
50
        public struct CFStreamClientContext {
50
51
                public int Version;
51
52
                public IntPtr Info;
52
53
                IntPtr retain;
88
89
                
89
90
                [MonoNativeFunctionWrapper]
90
91
                delegate IntPtr RetainDelegate (IntPtr info);
 
92
 
91
93
                static IntPtr CFReadStreamRef_InvokeRetain (IntPtr retain, IntPtr info)
92
94
                {
93
 
                        return ((RetainDelegate) Marshal.GetDelegateForFunctionPointer (retain, typeof (RetainDelegate))) (info);
 
95
                        return ((RetainDelegate)Marshal.GetDelegateForFunctionPointer (retain, typeof (RetainDelegate))) (info);
94
96
                }
95
97
                
96
98
                [MonoNativeFunctionWrapper]
97
99
                delegate void ReleaseDelegate (IntPtr info);
 
100
 
98
101
                static void CFReadStreamRef_InvokeRelease (IntPtr release, IntPtr info)
99
102
                {
100
 
                        ((ReleaseDelegate) Marshal.GetDelegateForFunctionPointer (release, typeof (ReleaseDelegate))) (info);
 
103
                        ((ReleaseDelegate)Marshal.GetDelegateForFunctionPointer (release, typeof (ReleaseDelegate))) (info);
101
104
                }
102
105
                
103
106
                [MonoNativeFunctionWrapper]
104
107
                delegate IntPtr CopyDescriptionDelegate (IntPtr info);
 
108
 
105
109
                static IntPtr CFReadStreamRef_InvokeCopyDescription (IntPtr copyDescription, IntPtr info)
106
110
                {
107
 
                        return ((CopyDescriptionDelegate) Marshal.GetDelegateForFunctionPointer (copyDescription, typeof (CopyDescriptionDelegate))) (info);
 
111
                        return ((CopyDescriptionDelegate)Marshal.GetDelegateForFunctionPointer (copyDescription, typeof (CopyDescriptionDelegate))) (info);
108
112
                }
109
113
                
110
114
                [MonoNativeFunctionWrapper]
111
115
                delegate void CallbackDelegate (IntPtr stream, CFStreamEventType eventType, IntPtr info);
 
116
 
112
117
                static void CFReadStreamRef_InvokeCallback (IntPtr callback, IntPtr stream, CFStreamEventType eventType, IntPtr info)
113
118
                {
114
 
                        ((CallbackDelegate) Marshal.GetDelegateForFunctionPointer (callback, typeof (CallbackDelegate))) (stream, eventType, info);
 
119
                        ((CallbackDelegate)Marshal.GetDelegateForFunctionPointer (callback, typeof (CallbackDelegate))) (stream, eventType, info);
 
120
                }
 
121
        }
 
122
 
 
123
        public enum CFStreamStatus {
 
124
                NotOpen = 0,
 
125
                Opening,
 
126
                Open,
 
127
                Reading,
 
128
                Writing,
 
129
                AtEnd,
 
130
                Closed,
 
131
                Error
 
132
        }
 
133
 
 
134
        public abstract class CFStream : CFType, INativeObject, IDisposable {
 
135
                IntPtr handle;
 
136
                GCHandle gch;
 
137
                CFRunLoop loop;
 
138
                NSString loopMode;
 
139
                bool open, closed;
 
140
 
 
141
                #region Stream Constructors
 
142
 
 
143
                [DllImport (Constants.CoreFoundationLibrary)]
 
144
                extern static void CFStreamCreatePairWithSocket (IntPtr allocator, CFSocketNativeHandle socket,
 
145
                                                                 out IntPtr read, out IntPtr write);
 
146
 
 
147
                public static void CreatePairWithSocket (CFSocket socket, out CFReadStream readStream,
 
148
                                                         out CFWriteStream writeStream)
 
149
                {
 
150
                        IntPtr read, write;
 
151
                        CFStreamCreatePairWithSocket (IntPtr.Zero, socket.GetNative (), out read, out write);
 
152
                        readStream = new CFReadStream (read);
 
153
                        writeStream = new CFWriteStream (write);
 
154
                }
 
155
 
 
156
                [DllImport (Constants.CFNetworkLibrary)]
 
157
                extern static void CFStreamCreatePairWithPeerSocketSignature (IntPtr allocator, ref CFSocketSignature sig, out IntPtr read, out IntPtr write);
 
158
 
 
159
                public static void CreatePairWithPeerSocketSignature (AddressFamily family, SocketType type,
 
160
                                                                      ProtocolType proto, IPEndPoint endpoint,
 
161
                                                                      out CFReadStream readStream,
 
162
                                                                      out CFWriteStream writeStream)
 
163
                {
 
164
                        using (var address = new CFSocketAddress (endpoint)) {
 
165
                                var sig = new CFSocketSignature (family, type, proto, address);
 
166
                                IntPtr read, write;
 
167
                                CFStreamCreatePairWithPeerSocketSignature (IntPtr.Zero, ref sig, out read, out write);
 
168
                                readStream = new CFReadStream (read);
 
169
                                writeStream = new CFWriteStream (write);
 
170
                        }
 
171
                }
 
172
 
 
173
                [DllImport (Constants.CFNetworkLibrary)]
 
174
                extern static void CFStreamCreatePairWithSocketToCFHost (IntPtr allocator, IntPtr host, int port,
 
175
                                                                         out IntPtr read, out IntPtr write);
 
176
 
 
177
                public static void CreatePairWithSocketToHost (IPEndPoint endpoint,
 
178
                                                               out CFReadStream readStream,
 
179
                                                               out CFWriteStream writeStream)
 
180
                {
 
181
                        using (var host = CFHost.Create (endpoint)) {
 
182
                                IntPtr read, write;
 
183
                                CFStreamCreatePairWithSocketToCFHost (
 
184
                                IntPtr.Zero, host.Handle, endpoint.Port, out read, out write);
 
185
                                readStream = new CFReadStream (read);
 
186
                                writeStream = new CFWriteStream (write);
 
187
                        }
 
188
                }
 
189
 
 
190
                [DllImport (Constants.CFNetworkLibrary)]
 
191
                extern static void CFStreamCreatePairWithSocketToHost (IntPtr allocator, IntPtr host, int port,
 
192
                                                                       out IntPtr read, out IntPtr write);
 
193
 
 
194
                public static void CreatePairWithSocketToHost (string host, int port,
 
195
                                                               out CFReadStream readStream,
 
196
                                                               out CFWriteStream writeStream)
 
197
                {
 
198
                        using (var str = new CFString (host)) {
 
199
                                IntPtr read, write;
 
200
                                CFStreamCreatePairWithSocketToHost (
 
201
                                        IntPtr.Zero, str.Handle, port, out read, out write);
 
202
                                readStream = new CFReadStream (read);
 
203
                                writeStream = new CFWriteStream (write);
 
204
                        }
 
205
                }
 
206
 
 
207
                [DllImport (Constants.CFNetworkLibrary)]
 
208
                extern static IntPtr CFReadStreamCreateForHTTPRequest (IntPtr alloc, IntPtr request);
 
209
 
 
210
                public static CFHTTPStream CreateForHTTPRequest (CFHTTPMessage request)
 
211
                {
 
212
                        var handle = CFReadStreamCreateForHTTPRequest (IntPtr.Zero, request.Handle);
 
213
                        if (handle == IntPtr.Zero)
 
214
                                return null;
 
215
 
 
216
                        return new CFHTTPStream (handle);
 
217
                }
 
218
 
 
219
                [DllImport (Constants.CFNetworkLibrary)]
 
220
                extern static IntPtr CFReadStreamCreateForStreamedHTTPRequest (IntPtr alloc, IntPtr request, IntPtr body);
 
221
 
 
222
                public static CFHTTPStream CreateForStreamedHTTPRequest (CFHTTPMessage request, CFReadStream body)
 
223
                {
 
224
                        var handle = CFReadStreamCreateForStreamedHTTPRequest (IntPtr.Zero, request.Handle, body.Handle);
 
225
                        if (handle == IntPtr.Zero)
 
226
                                return null;
 
227
 
 
228
                        return new CFHTTPStream (handle);
 
229
                }
 
230
 
 
231
                [DllImport (Constants.CFNetworkLibrary)]
 
232
                extern static void CFStreamCreateBoundPair (IntPtr alloc, out IntPtr readStream, out IntPtr writeStream, CFIndex transferBufferSize);
 
233
 
 
234
                public static void CreateBoundPair (out CFReadStream readStream, out CFWriteStream writeStream, int bufferSize)
 
235
                {
 
236
                        IntPtr read, write;
 
237
                        CFStreamCreateBoundPair (IntPtr.Zero, out read, out write, bufferSize);
 
238
                        readStream = new CFReadStream (read);
 
239
                        writeStream = new CFWriteStream (write);
 
240
                }
 
241
 
 
242
                #endregion
 
243
 
 
244
                #region Stream API
 
245
 
 
246
                public abstract CFException GetError ();
 
247
 
 
248
                protected void CheckError ()
 
249
                {
 
250
                        var exc = GetError ();
 
251
                        if (exc != null)
 
252
                                throw exc;
 
253
                }
 
254
 
 
255
                public void Open ()
 
256
                {
 
257
                        if (open || closed)
 
258
                                throw new InvalidOperationException ();
 
259
                        CheckHandle ();
 
260
                        if (!DoOpen ()) {
 
261
                                CheckError ();
 
262
                                throw new InvalidOperationException ();
 
263
                        }
 
264
                        open = true;
 
265
                }
 
266
 
 
267
                protected abstract bool DoOpen ();
 
268
 
 
269
                public void Close ()
 
270
                {
 
271
                        if (!open)
 
272
                                return;
 
273
                        CheckHandle ();
 
274
                        if (loop != null) {
 
275
                                DoSetClient (null, 0, IntPtr.Zero);
 
276
                                UnscheduleFromRunLoop (loop, loopMode);
 
277
                                loop = null;
 
278
                                loopMode = null;
 
279
                        }
 
280
                        try {
 
281
                                DoClose ();
 
282
                        } finally {
 
283
                                open = false;
 
284
                                closed = true;
 
285
                        }
 
286
                }
 
287
 
 
288
                protected abstract void DoClose ();
 
289
 
 
290
                public CFStreamStatus GetStatus ()
 
291
                {
 
292
                        CheckHandle ();
 
293
                        return DoGetStatus ();
 
294
                }
 
295
 
 
296
                protected abstract CFStreamStatus DoGetStatus ();
 
297
 
 
298
                internal IntPtr GetProperty (NSString name)
 
299
                {
 
300
                        CheckHandle ();
 
301
                        return DoGetProperty (name);
 
302
                }
 
303
 
 
304
                protected abstract IntPtr DoGetProperty (NSString name);
 
305
 
 
306
                protected abstract bool DoSetProperty (NSString name, INativeObject value);
 
307
 
 
308
                internal void SetProperty (NSString name, INativeObject value)
 
309
                {
 
310
                        CheckHandle ();
 
311
                        if (DoSetProperty (name, value))
 
312
                                return;
 
313
                        throw new InvalidOperationException (string.Format (
 
314
                                "Cannot set property '{0}' on {1}.", name, GetType ().Name)
 
315
                        );
 
316
                }
 
317
 
 
318
                #endregion
 
319
 
 
320
                #region Events
 
321
 
 
322
                public class StreamEventArgs : EventArgs {
 
323
                        public CFStreamEventType EventType {
 
324
                                get;
 
325
                                private set;
 
326
                        }
 
327
 
 
328
                        public StreamEventArgs (CFStreamEventType type)
 
329
                        {
 
330
                                this.EventType = type;
 
331
                        }
 
332
 
 
333
                        public override string ToString ()
 
334
                        {
 
335
                                return string.Format ("[StreamEventArgs: EventType={0}]", EventType);
 
336
                        }
 
337
                }
 
338
 
 
339
                public event EventHandler<StreamEventArgs> OpenCompletedEvent;
 
340
                public event EventHandler<StreamEventArgs> HasBytesAvailableEvent;
 
341
                public event EventHandler<StreamEventArgs> CanAcceptBytesEvent;
 
342
                public event EventHandler<StreamEventArgs> ErrorEvent;
 
343
                public event EventHandler<StreamEventArgs> ClosedEvent;
 
344
 
 
345
                protected virtual void OnOpenCompleted (StreamEventArgs args)
 
346
                {
 
347
                        if (OpenCompletedEvent != null)
 
348
                                OpenCompletedEvent (this, args);
 
349
                }
 
350
 
 
351
                protected virtual void OnHasBytesAvailableEvent (StreamEventArgs args)
 
352
                {
 
353
                        if (HasBytesAvailableEvent != null)
 
354
                                HasBytesAvailableEvent (this, args);
 
355
                }
 
356
 
 
357
                protected virtual void OnCanAcceptBytesEvent (StreamEventArgs args)
 
358
                {
 
359
                        if (CanAcceptBytesEvent != null)
 
360
                                CanAcceptBytesEvent (this, args);
 
361
                }
 
362
 
 
363
                protected virtual void OnErrorEvent (StreamEventArgs args)
 
364
                {
 
365
                        if (ErrorEvent != null)
 
366
                                ErrorEvent (this, args);
 
367
                }
 
368
 
 
369
                protected virtual void OnClosedEvent (StreamEventArgs args)
 
370
                {
 
371
                        if (ClosedEvent != null)
 
372
                                ClosedEvent (this, args);
 
373
                }
 
374
 
 
375
                #endregion
 
376
 
 
377
                protected abstract void ScheduleWithRunLoop (CFRunLoop loop, NSString mode);
 
378
 
 
379
                protected abstract void UnscheduleFromRunLoop (CFRunLoop loop, NSString mode);
 
380
 
 
381
                protected delegate void CFStreamCallback (IntPtr s, CFStreamEventType type, IntPtr info);
 
382
 
 
383
                [MonoPInvokeCallback (typeof(CFStreamCallback))]
 
384
                static void OnCallback (IntPtr s, CFStreamEventType type, IntPtr info)
 
385
                {
 
386
                        var stream = GCHandle.FromIntPtr (info).Target as CFStream;
 
387
                        stream.OnCallback (type);
 
388
                }
 
389
 
 
390
                protected virtual void OnCallback (CFStreamEventType type)
 
391
                {
 
392
                        var args = new StreamEventArgs (type);
 
393
                        switch (type) {
 
394
                        case CFStreamEventType.OpenCompleted:
 
395
                                OnOpenCompleted (args);
 
396
                                break;
 
397
                        case CFStreamEventType.CanAcceptBytes:
 
398
                                OnCanAcceptBytesEvent (args);
 
399
                                break;
 
400
                        case CFStreamEventType.HasBytesAvailable:
 
401
                                OnHasBytesAvailableEvent (args);
 
402
                                break;
 
403
                        case CFStreamEventType.ErrorOccurred:
 
404
                                OnErrorEvent (args);
 
405
                                break;
 
406
                        case CFStreamEventType.EndEncountered:
 
407
                                OnClosedEvent (args);
 
408
                                break;
 
409
                        }
 
410
                }
 
411
 
 
412
                public void EnableEvents (CFRunLoop runLoop, NSString runLoopMode)
 
413
                {
 
414
                        if (open || closed || (loop != null))
 
415
                                throw new InvalidOperationException ();
 
416
                        CheckHandle ();
 
417
 
 
418
                        loop = runLoop;
 
419
                        loopMode = runLoopMode;
 
420
 
 
421
                        var ctx = new CFStreamClientContext ();
 
422
                        ctx.Info = GCHandle.ToIntPtr (gch);
 
423
 
 
424
                        var args = CFStreamEventType.OpenCompleted |
 
425
                                CFStreamEventType.CanAcceptBytes | CFStreamEventType.HasBytesAvailable |
 
426
                                CFStreamEventType.CanAcceptBytes | CFStreamEventType.ErrorOccurred |
 
427
                                CFStreamEventType.EndEncountered;
 
428
 
 
429
                        var ptr = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (CFStreamClientContext)));
 
430
                        try {
 
431
                                Marshal.StructureToPtr (ctx, ptr, false);
 
432
                                if (!DoSetClient (OnCallback, (int)args, ptr))
 
433
                                        throw new InvalidOperationException ("Stream does not support async events.");
 
434
                        } finally {
 
435
                                Marshal.FreeHGlobal (ptr);
 
436
                        }
 
437
 
 
438
                        ScheduleWithRunLoop (runLoop, runLoopMode);
 
439
                }
 
440
 
 
441
                protected abstract bool DoSetClient (CFStreamCallback callback, CFIndex eventTypes,
 
442
                                                     IntPtr context);
 
443
 
 
444
                protected CFStream (IntPtr handle)
 
445
                {
 
446
                        this.handle = handle;
 
447
                        gch = GCHandle.Alloc (this);
 
448
                }
 
449
 
 
450
                protected void CheckHandle ()
 
451
                {
 
452
                        if (handle == IntPtr.Zero)
 
453
                                throw new ObjectDisposedException (GetType ().Name);
 
454
                }
 
455
 
 
456
                ~CFStream ()
 
457
                {
 
458
                        Dispose (false);
 
459
                }
 
460
                
 
461
                public void Dispose ()
 
462
                {
 
463
                        Dispose (true);
 
464
                        GC.SuppressFinalize (this);
 
465
                }
 
466
 
 
467
                public IntPtr Handle {
 
468
                        get { return handle; }
 
469
                }
 
470
                
 
471
                protected virtual void Dispose (bool disposing)
 
472
                {
 
473
                        if (disposing) {
 
474
                                Close ();
 
475
                                if (gch.IsAllocated)
 
476
                                        gch.Free ();
 
477
                        }
 
478
                        if (handle != IntPtr.Zero) {
 
479
                                CFObject.CFRelease (handle);
 
480
                                handle = IntPtr.Zero;
 
481
                        }
115
482
                }
116
483
        }
117
484
}