Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System / net / System / Net / Sockets / NetworkStream.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="NetworkStream.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net.Sockets {
8     using System.IO;
9     using System.Runtime.InteropServices;
10     using System.Threading;
11     using System.Security.Permissions;
12     using System.Threading.Tasks;
13
14     /// <devdoc>
15     ///    <para>
16     ///       Provides the underlying stream of data for network access.
17     ///    </para>
18     /// </devdoc>
19     public class NetworkStream : Stream {
20         /// <devdoc>
21         ///    <para>
22         ///       Used by the class to hold the underlying socket the stream uses.
23         ///    </para>
24         /// </devdoc>
25         private Socket    m_StreamSocket;
26
27         /// <devdoc>
28         ///    <para>
29         ///       Used by the class to indicate that the stream is m_Readable.
30         ///    </para>
31         /// </devdoc>
32         private bool      m_Readable;
33
34         /// <devdoc>
35         ///    <para>
36         ///       Used by the class to indicate that the stream is writable.
37         ///    </para>
38         /// </devdoc>
39         private bool      m_Writeable;
40
41         private bool      m_OwnsSocket;
42
43         /// <devdoc>
44         /// <para>Creates a new instance of the <see cref='System.Net.Sockets.NetworkStream'/> without initalization.</para>
45         /// </devdoc>
46         internal NetworkStream() {
47             m_OwnsSocket = true;
48         }
49
50
51         // Can be constructed directly out of a socket
52         /// <devdoc>
53         /// <para>Creates a new instance of the <see cref='System.Net.Sockets.NetworkStream'/> class for the specified <see cref='System.Net.Sockets.Socket'/>.</para>
54         /// </devdoc>
55         public NetworkStream(Socket socket) {
56 #if DEBUG
57             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
58 #endif
59             if (socket == null) {
60                 throw new ArgumentNullException("socket");
61             }
62             InitNetworkStream(socket, FileAccess.ReadWrite);
63 #if DEBUG
64             }
65 #endif
66         }
67
68         //UEUE (see FileStream)
69         // ownsHandle: true if the file handle will be owned by this NetworkStream instance; otherwise, false.
70         public NetworkStream(Socket socket, bool ownsSocket) {
71 #if DEBUG
72             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
73 #endif
74             if (socket == null) {
75                 throw new ArgumentNullException("socket");
76             }
77             InitNetworkStream(socket, FileAccess.ReadWrite);
78             m_OwnsSocket = ownsSocket;
79 #if DEBUG
80             }
81 #endif
82         }
83
84         internal NetworkStream(NetworkStream networkStream, bool ownsSocket) {
85             Socket socket = networkStream.Socket;
86             if (socket == null) {
87                 throw new ArgumentNullException("networkStream");
88             }
89             InitNetworkStream(socket, FileAccess.ReadWrite);
90             m_OwnsSocket = ownsSocket;
91         }
92
93         // Create with a socket and access mode
94         /// <devdoc>
95         /// <para>Creates a new instance of the <see cref='System.Net.Sockets.NetworkStream'/> class for the specified <see cref='System.Net.Sockets.Socket'/> with the specified access rights.</para>
96         /// </devdoc>
97         public NetworkStream(Socket socket, FileAccess access) {
98 #if DEBUG
99             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
100 #endif
101             if (socket == null) {
102                 throw new ArgumentNullException("socket");
103             }
104             InitNetworkStream(socket, access);
105 #if DEBUG
106             }
107 #endif
108         }
109         public NetworkStream(Socket socket, FileAccess access, bool ownsSocket) {
110 #if DEBUG
111             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
112 #endif
113             if (socket == null) {
114                 throw new ArgumentNullException("socket");
115             }
116             InitNetworkStream(socket, access);
117             m_OwnsSocket = ownsSocket;
118 #if DEBUG
119             }
120 #endif
121         }
122
123         //
124         // Socket - provides access to socket for stream closing
125         //
126         protected Socket Socket {
127             get {
128                 return m_StreamSocket;
129             }
130         }
131
132         internal Socket InternalSocket {
133             get {
134                 Socket chkSocket = m_StreamSocket;
135                 if (m_CleanedUp || chkSocket == null) {
136                     throw new ObjectDisposedException(this.GetType().FullName);
137                 }
138
139                 return chkSocket;
140             }
141         }
142
143         internal void InternalAbortSocket() 
144         {
145             if (!m_OwnsSocket)
146             {
147                 throw new InvalidOperationException();
148             }
149
150             Socket chkSocket = m_StreamSocket;
151             if (m_CleanedUp || chkSocket == null)
152             {
153                 return;
154             }
155
156             try
157             {
158                 chkSocket.Close(0);
159             }
160             catch (ObjectDisposedException)
161             {
162             }
163         }
164
165         internal void ConvertToNotSocketOwner() {
166             m_OwnsSocket = false;
167             // Suppress for finialization still allow proceed the requests
168             GC.SuppressFinalize(this);
169         }
170
171         /// <devdoc>
172         ///    <para>
173         ///       Used by the class to indicate that the stream is m_Readable.
174         ///    </para>
175         /// </devdoc>
176         protected bool Readable {
177             get {
178                 return m_Readable;
179             }
180             set {
181                 m_Readable = value;
182             }
183         }
184
185         /// <devdoc>
186         ///    <para>
187         ///       Used by the class to indicate that the stream is writable.
188         ///    </para>
189         /// </devdoc>
190         protected bool Writeable {
191             get {
192                 return m_Writeable;
193             }
194             set {
195                 m_Writeable = value;
196             }
197         }
198
199
200         /// <devdoc>
201         ///    <para>
202         ///       Indicates that data can be read from the stream.
203         ///         We return the readability of this stream. This is a read only property.
204         ///    </para>
205         /// </devdoc>
206         public override bool CanRead {
207             get {
208                 return m_Readable;
209             }
210         }
211
212
213         /// <devdoc>
214         ///    <para>
215         ///       Indicates that the stream can seek a specific location
216         ///       in the stream. This property always returns <see langword='false'/>
217         ///       .
218         ///    </para>
219         /// </devdoc>
220         public override bool CanSeek {
221             get {
222                 return false;
223             }
224         }
225
226
227         /// <devdoc>
228         ///    <para>
229         ///       Indicates that data can be written to the stream.
230         ///    </para>
231         /// </devdoc>
232         public override bool CanWrite {
233             get {
234                 return m_Writeable;
235             }
236         }
237
238
239         /// <devdoc>
240         ///    <para>Indicates whether we can timeout</para>
241         /// </devdoc>
242         public override bool CanTimeout { 
243             get {
244                 return true; // should we check for Connected state?
245             }
246         }
247
248
249         /// <devdoc>
250         ///    <para>Set/Get ReadTimeout, note of a strange behavior, 0 timeout == infinite for sockets,
251         ///         so we map this to -1, and if you set 0, we cannot support it</para>
252         /// </devdoc>
253         public override int ReadTimeout { 
254             get {
255 #if DEBUG
256                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
257 #endif
258                 int timeout = (int)m_StreamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
259                 if (timeout == 0) {
260                     return -1;
261                 }
262                 return timeout;
263 #if DEBUG
264                 }
265 #endif
266             }
267             set {
268 #if DEBUG
269                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
270 #endif
271                 if (value<=0 && value!=System.Threading.Timeout.Infinite) {
272                     throw new ArgumentOutOfRangeException("value", SR.GetString(SR.net_io_timeout_use_gt_zero));
273                 }
274                 SetSocketTimeoutOption(SocketShutdown.Receive, value, false);
275 #if DEBUG
276                 }
277 #endif
278             }
279         }
280
281         /// <devdoc>
282         ///    <para>Set/Get WriteTimeout, note of a strange behavior, 0 timeout == infinite for sockets,
283         ///         so we map this to -1, and if you set 0, we cannot support it</para>
284         /// </devdoc>
285             public override int WriteTimeout { 
286             get {
287 #if DEBUG
288                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
289 #endif
290                 int timeout = (int)m_StreamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
291                 if (timeout == 0) {
292                     return -1;
293                 }
294                 return timeout;
295 #if DEBUG
296                 }
297 #endif
298             }
299             set {
300 #if DEBUG
301                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
302 #endif
303                 if (value <= 0 && value != System.Threading.Timeout.Infinite) {
304                     throw new ArgumentOutOfRangeException("value", SR.GetString(SR.net_io_timeout_use_gt_zero));
305                 }
306                 SetSocketTimeoutOption(SocketShutdown.Send, value, false);
307 #if DEBUG
308                 }
309 #endif
310             }
311         }        
312
313         /// <devdoc>
314         ///    <para>
315         ///       Indicates data is available on the stream to be read.
316         ///         This property checks to see if at least one byte of data is currently available            
317         ///    </para>
318         /// </devdoc>
319         public virtual bool DataAvailable {
320             get {
321 #if DEBUG
322                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
323 #endif
324                 if (m_CleanedUp){
325                     throw new ObjectDisposedException(this.GetType().FullName);
326                 }
327
328                 Socket chkStreamSocket = m_StreamSocket;
329                 if(chkStreamSocket == null) {
330                     throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
331                 }
332
333                 // Ask the socket how many bytes are available. If it's
334                 // not zero, return true.
335
336                 return chkStreamSocket.Available != 0;
337 #if DEBUG
338                 }
339 #endif
340             }
341         }
342
343
344         /// <devdoc>
345         ///    <para>
346         ///       The length of data available on the stream. Always throws <see cref='NotSupportedException'/>.
347         ///    </para>
348         /// </devdoc>
349         public override long Length {
350             get {
351                 throw new NotSupportedException(SR.GetString(SR.net_noseek));
352             }
353         }
354
355         /// <devdoc>
356         ///    <para>
357         ///       Gets or sets the position in the stream. Always throws <see cref='NotSupportedException'/>.
358         ///    </para>
359         /// </devdoc>
360         public override long Position {
361             get {
362                 throw new NotSupportedException(SR.GetString(SR.net_noseek));
363             }
364
365             set {
366                 throw new NotSupportedException(SR.GetString(SR.net_noseek));
367             }
368         }
369
370
371         /// <devdoc>
372         ///    <para>
373         ///       Seeks a specific position in the stream. This method is not supported by the
374         ///    <see cref='NetworkStream'/> class.
375         ///    </para>
376         /// </devdoc>
377         public override long Seek(long offset, SeekOrigin origin) {
378             throw new NotSupportedException(SR.GetString(SR.net_noseek));
379         }
380
381
382         /*++
383
384             InitNetworkStream - initialize a network stream.
385
386             This is the common NetworkStream constructor, called whenever a
387             network stream is created. We validate the socket, set a few
388             options, and call our parent's initializer.
389
390             Input:
391
392                 S           - Socket to be used.
393                 Access      - Access type desired.
394
395
396             Returns:
397
398                 Nothing, but may throw an exception.
399         --*/
400
401         internal void InitNetworkStream(Socket socket, FileAccess Access) {
402             //
403             // parameter validation
404             //
405             if (!socket.Blocking) {
406                 throw new IOException(SR.GetString(SR.net_sockets_blocking));
407             }
408             if (!socket.Connected) {
409                 throw new IOException(SR.GetString(SR.net_notconnected));
410             }
411             if (socket.SocketType != SocketType.Stream) {
412                 throw new IOException(SR.GetString(SR.net_notstream));
413             }
414
415             m_StreamSocket = socket;
416
417             switch (Access) {
418                 case FileAccess.Read:
419                     m_Readable = true;
420                     break;
421                 case FileAccess.Write:
422                     m_Writeable = true;
423                     break;
424                 case FileAccess.ReadWrite:
425                 default: // assume FileAccess.ReadWrite
426                     m_Readable = true;
427                     m_Writeable = true;
428                     break;
429             }
430
431         }
432
433         internal bool PollRead() {
434             if (m_CleanedUp) {
435                 return false;
436             }
437             Socket chkStreamSocket = m_StreamSocket;
438             if (chkStreamSocket == null) {
439                 return false;
440             }
441             return chkStreamSocket.Poll(0, SelectMode.SelectRead);
442         }
443
444         internal bool Poll(int microSeconds, SelectMode mode) {
445             if (m_CleanedUp){
446                 throw new ObjectDisposedException(this.GetType().FullName);
447             }
448
449             Socket chkStreamSocket = m_StreamSocket;
450             if (chkStreamSocket == null) {
451                 throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
452             }
453
454             return chkStreamSocket.Poll(microSeconds, mode);
455         }
456
457
458         /*++
459             Read - provide core Read functionality.
460
461             Provide core read functionality. All we do is call through to the
462             socket Receive functionality.
463
464             Input:
465
466                 Buffer  - Buffer to read into.
467                 Offset  - Offset into the buffer where we're to read.
468                 Count   - Number of bytes to read.
469
470             Returns:
471
472                 Number of bytes we read, or 0 if the socket is closed.
473
474         --*/
475
476         /// <devdoc>
477         ///    <para>
478         ///       Reads data from the stream.
479         ///    </para>
480         /// </devdoc>
481         //UEUE
482         public override int Read([In, Out] byte[] buffer, int offset, int size) {
483 #if DEBUG
484             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) {
485 #endif
486             bool canRead = CanRead;  // Prevent race with Dispose.
487             if (m_CleanedUp){
488                 throw new ObjectDisposedException(this.GetType().FullName);
489             }
490             if (!canRead) {    
491                 throw new InvalidOperationException(SR.GetString(SR.net_writeonlystream));
492             }
493             //
494             // parameter validation
495             //
496             if (buffer==null) {
497                 throw new ArgumentNullException("buffer");
498             }
499             if (offset<0 || offset>buffer.Length) {
500                 throw new ArgumentOutOfRangeException("offset");
501             }
502             if (size<0 || size>buffer.Length-offset) {
503                 throw new ArgumentOutOfRangeException("size");
504             }
505
506
507             Socket chkStreamSocket = m_StreamSocket;
508             if (chkStreamSocket == null) {
509                 throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
510             }
511
512             try {
513                 int bytesTransferred = chkStreamSocket.Receive(buffer, offset, size, 0);
514                 return bytesTransferred;
515             }
516             catch (Exception exception) {
517                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
518                     throw;
519                     }
520
521                 //
522                 // some sort of error occured on the socket call,
523                 // set the SocketException as InnerException and throw
524                 //
525                 throw new IOException(SR.GetString(SR.net_io_readfailure, exception.Message), exception);
526             }
527 #if DEBUG
528             }
529 #endif
530         }
531
532         /*++
533             Write - provide core Write functionality.
534
535             Provide core write functionality. All we do is call through to the
536             socket Send method..
537
538             Input:
539
540                 Buffer  - Buffer to write from.
541                 Offset  - Offset into the buffer from where we'll start writing.
542                 Count   - Number of bytes to write.
543
544             Returns:
545
546                 Number of bytes written. We'll throw an exception if we
547                 can't write everything. It's brutal, but there's no other
548                 way to indicate an error.
549         --*/
550
551         /// <devdoc>
552         ///    <para>
553         ///       Writes data to the stream..
554         ///    </para>
555         /// </devdoc>
556         public override void Write(byte[] buffer, int offset, int size) {
557 #if DEBUG
558             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) {
559 #endif
560             bool canWrite = CanWrite; // Prevent race with Dispose.
561             if (m_CleanedUp){
562                 throw new ObjectDisposedException(this.GetType().FullName);
563             }
564             if (!canWrite) {    
565                 throw new InvalidOperationException(SR.GetString(SR.net_readonlystream));
566             }
567             //
568             // parameter validation
569             //
570             if (buffer==null) {
571                 throw new ArgumentNullException("buffer");
572             }
573             if (offset<0 || offset>buffer.Length) {
574                 throw new ArgumentOutOfRangeException("offset");
575             }
576             if (size<0 || size>buffer.Length-offset) {
577                 throw new ArgumentOutOfRangeException("size");
578             }
579
580
581             Socket chkStreamSocket = m_StreamSocket;
582             if(chkStreamSocket == null) {
583                 throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
584             }
585
586             try {
587                 //
588                 // since the socket is in blocking mode this will always complete
589                 // after ALL the requested number of bytes was transferred
590                 //
591                 chkStreamSocket.Send(buffer, offset, size, SocketFlags.None);
592             }
593             catch (Exception exception) {
594                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
595                     throw;
596                     }
597
598                 //
599                 // some sort of error occured on the socket call,
600                 // set the SocketException as InnerException and throw
601                 //
602                 throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
603             }
604 #if DEBUG
605             }
606 #endif
607         }
608
609         private int m_CloseTimeout = Socket.DefaultCloseTimeout; // 1 ms; -1 = respect linger options
610
611         public void Close(int timeout) {
612 #if DEBUG
613             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) {
614 #endif
615             if (timeout < -1) {
616                 throw new ArgumentOutOfRangeException("timeout");
617             }
618             m_CloseTimeout = timeout;
619             Close();
620 #if DEBUG
621             }
622 #endif
623         }
624
625         private volatile bool m_CleanedUp = false;
626         protected override void Dispose(bool disposing) {
627 #if DEBUG
628             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
629 #endif
630             // Mark this as disposed before changing anything else.
631             bool cleanedUp = m_CleanedUp;
632             m_CleanedUp = true; 
633             if (!cleanedUp && disposing) {
634                 //
635                 // only resource we need to free is the network stream, since this
636                 // is based on the client socket, closing the stream will cause us
637                 // to flush the data to the network, close the stream and (in the
638                 // NetoworkStream code) close the socket as well.
639                 //
640                 if (m_StreamSocket!=null) {
641                     m_Readable = false;
642                     m_Writeable = false;
643                     if (m_OwnsSocket) {
644                         //
645                         // if we own the Socket (false by default), close it
646                         // ignoring possible exceptions (eg: the user told us
647                         // that we own the Socket but it closed at some point of time,
648                         // here we would get an ObjectDisposedException)
649                         //
650                         Socket chkStreamSocket = m_StreamSocket;
651                         if (chkStreamSocket!=null) {
652                             chkStreamSocket.InternalShutdown(SocketShutdown.Both);
653                             chkStreamSocket.Close(m_CloseTimeout);
654                         }
655                     }
656                 }
657             }
658 #if DEBUG
659             }
660 #endif
661             base.Dispose(disposing);
662         }
663
664         ~NetworkStream() {
665 #if DEBUG
666             GlobalLog.SetThreadSource(ThreadKinds.Finalization);
667            // using (GlobalLog.SetThreadKind(ThreadKinds.System | ThreadKinds.Async)) {
668 #endif
669             Dispose(false);
670 #if DEBUG
671            // }
672 #endif
673         }
674
675         /// <devdoc>
676         ///    <para>
677         ///       Indicates whether the stream is still connected
678         ///    </para>
679         /// </devdoc>
680         internal bool Connected {
681             get {
682                 Socket socket = m_StreamSocket;
683                 if (!m_CleanedUp && socket !=null && socket.Connected) {
684                     return true;
685                 } else {
686                     return false;
687                 }
688             }
689         }
690
691
692         /*++
693             BeginRead - provide async read functionality.
694
695             This method provides async read functionality. All we do is
696             call through to the underlying socket async read.
697
698             Input:
699
700                 buffer  - Buffer to read into.
701                 offset  - Offset into the buffer where we're to read.
702                 size   - Number of bytes to read.
703
704             Returns:
705
706                 An IASyncResult, representing the read.
707
708         --*/
709
710         /// <devdoc>
711         ///    <para>
712         ///       Begins an asychronous read from a stream.
713         ///    </para>
714         /// </devdoc>
715         [HostProtection(ExternalThreading=true)]
716         public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
717 #if DEBUG
718             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
719 #endif
720             bool canRead = CanRead; // Prevent race with Dispose.
721             if (m_CleanedUp){
722                 throw new ObjectDisposedException(this.GetType().FullName);
723             }
724             if (!canRead) {    
725                 throw new InvalidOperationException(SR.GetString(SR.net_writeonlystream));
726             }
727             //
728             // parameter validation
729             //
730             if (buffer==null) {
731                 throw new ArgumentNullException("buffer");
732             }
733             if (offset<0 || offset>buffer.Length) {
734                 throw new ArgumentOutOfRangeException("offset");
735             }
736             if (size<0 || size>buffer.Length-offset) {
737                 throw new ArgumentOutOfRangeException("size");
738             }
739
740             Socket chkStreamSocket = m_StreamSocket;
741             if(chkStreamSocket == null) {
742                 throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
743             }
744
745             try {
746                 IAsyncResult asyncResult =
747                     chkStreamSocket.BeginReceive(
748                         buffer,
749                         offset,
750                         size,
751                         SocketFlags.None,
752                         callback,
753                         state);
754
755                 return asyncResult;
756             }
757             catch (Exception exception) {
758                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
759                     throw;
760                     }
761
762                 //
763                 // some sort of error occured on the socket call,
764                 // set the SocketException as InnerException and throw
765                 //
766                 throw new IOException(SR.GetString(SR.net_io_readfailure, exception.Message), exception);
767             }
768 #if DEBUG
769             }
770 #endif
771         }
772
773         internal virtual IAsyncResult UnsafeBeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, Object state)
774         {
775             bool canRead = CanRead; // Prevent race with Dispose.
776             if (m_CleanedUp)
777             {
778                 throw new ObjectDisposedException(GetType().FullName);
779             }
780             if (!canRead)
781             {
782                 throw new InvalidOperationException(SR.GetString(SR.net_writeonlystream));
783             }
784
785             Socket chkStreamSocket = m_StreamSocket;
786             if (chkStreamSocket == null)
787             {
788                 throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
789             }
790
791             try
792             {
793                 IAsyncResult asyncResult = chkStreamSocket.UnsafeBeginReceive(
794                     buffer,
795                     offset,
796                     size,
797                     SocketFlags.None,
798                     callback,
799                     state);
800
801                 return asyncResult;
802             }
803             catch (Exception exception)
804             {
805                 if (NclUtilities.IsFatal(exception)) throw;
806
807                 //
808                 // some sort of error occured on the socket call,
809                 // set the SocketException as InnerException and throw
810                 //
811                 throw new IOException(SR.GetString(SR.net_io_readfailure, exception.Message), exception);
812             }
813         }
814
815         /*++
816             EndRead - handle the end of an async read.
817
818             This method is called when an async read is completed. All we
819             do is call through to the core socket EndReceive functionality.
820             Input:
821
822                 buffer  - Buffer to read into.
823                 offset  - Offset into the buffer where we're to read.
824                 size   - Number of bytes to read.
825
826             Returns:
827
828                 The number of bytes read. May throw an exception.
829
830         --*/
831
832         /// <devdoc>
833         ///    <para>
834         ///       Handle the end of an asynchronous read.
835         ///    </para>
836         /// </devdoc>
837         public override int EndRead(IAsyncResult asyncResult) {
838 #if DEBUG
839             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
840 #endif
841             if (m_CleanedUp){
842                 throw new ObjectDisposedException(this.GetType().FullName);
843             }
844
845             //
846             // parameter validation
847             //
848             if (asyncResult==null) {
849                 throw new ArgumentNullException("asyncResult");
850             }
851
852             Socket chkStreamSocket = m_StreamSocket;
853             if(chkStreamSocket == null) {
854                 throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
855             }
856
857             try {
858                 int bytesTransferred = chkStreamSocket.EndReceive(asyncResult);
859                 return bytesTransferred;
860             }
861             catch (Exception exception) {
862                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
863                     throw;
864                     }
865
866                 //
867                 // some sort of error occured on the socket call,
868                 // set the SocketException as InnerException and throw
869                 //
870                 throw new IOException(SR.GetString(SR.net_io_readfailure, exception.Message), exception);
871             }
872 #if DEBUG
873             }
874 #endif
875         }
876
877         /*++
878             BeginWrite - provide async write functionality.
879
880             This method provides async write functionality. All we do is
881             call through to the underlying socket async send.
882
883             Input:
884
885                 buffer  - Buffer to write into.
886                 offset  - Offset into the buffer where we're to write.
887                 size   - Number of bytes to written.
888
889             Returns:
890
891                 An IASyncResult, representing the write.
892
893         --*/
894
895         /// <devdoc>
896         ///    <para>
897         ///       Begins an asynchronous write to a stream.
898         ///    </para>
899         /// </devdoc>
900         [HostProtection(ExternalThreading=true)]
901         public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
902 #if DEBUG
903             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
904 #endif
905             bool canWrite = CanWrite; // Prevent race with Dispose.
906             if (m_CleanedUp){
907                 throw new ObjectDisposedException(this.GetType().FullName);
908             }
909             if (!canWrite) {    
910                 throw new InvalidOperationException(SR.GetString(SR.net_readonlystream));
911             }
912             //
913             // parameter validation
914             //
915             if (buffer==null) {
916                 throw new ArgumentNullException("buffer");
917             }
918             if (offset<0 || offset>buffer.Length) {
919                 throw new ArgumentOutOfRangeException("offset");
920             }
921             if (size<0 || size>buffer.Length-offset) {
922                 throw new ArgumentOutOfRangeException("size");
923             }
924
925             Socket chkStreamSocket = m_StreamSocket;
926             if(chkStreamSocket == null) {
927                 throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
928             }
929
930             try {
931                 //
932                 // call BeginSend on the Socket.
933                 //
934                 IAsyncResult asyncResult =
935                     chkStreamSocket.BeginSend(
936                         buffer,
937                         offset,
938                         size,
939                         SocketFlags.None,
940                         callback,
941                         state);
942
943                 return asyncResult;
944             }
945             catch (Exception exception) {
946                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
947                     throw;
948                     }
949
950                 //
951                 // some sort of error occured on the socket call,
952                 // set the SocketException as InnerException and throw
953                 //
954                 throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
955             }
956 #if DEBUG
957             }
958 #endif
959         }
960
961                
962
963         internal virtual IAsyncResult UnsafeBeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
964 #if DEBUG
965             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
966 #endif
967                 bool canWrite = CanWrite; // Prevent race with Dispose.
968                 if (m_CleanedUp){
969                     throw new ObjectDisposedException(this.GetType().FullName);
970                 }
971                 
972                 if (!canWrite) {    
973                     throw new InvalidOperationException(SR.GetString(SR.net_readonlystream));
974                 }
975     
976                 Socket chkStreamSocket = m_StreamSocket;
977                 if(chkStreamSocket == null) {
978                     throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
979                 }
980     
981                 try {
982                     //
983                     // call BeginSend on the Socket.
984                     //
985                     IAsyncResult asyncResult =
986                         chkStreamSocket.UnsafeBeginSend(
987                             buffer,
988                             offset,
989                             size,
990                             SocketFlags.None,
991                             callback,
992                             state);
993     
994                     return asyncResult;
995                 }
996                 catch (Exception exception) {
997                     if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
998                         throw;
999                     }
1000     
1001                     //
1002                     // some sort of error occured on the socket call,
1003                     // set the SocketException as InnerException and throw
1004                     //
1005                     throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
1006                 }
1007 #if DEBUG
1008             }
1009 #endif
1010         }
1011
1012
1013
1014         /// <devdoc>
1015         ///    <para>
1016         ///       Handle the end of an asynchronous write.
1017         ///       This method is called when an async write is completed. All we
1018         ///       do is call through to the core socket EndSend functionality.
1019         ///       Returns:  The number of bytes read. May throw an exception.
1020         ///    </para>
1021         /// </devdoc>
1022         public override void EndWrite(IAsyncResult asyncResult) {
1023 #if DEBUG
1024             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
1025 #endif
1026             if (m_CleanedUp){
1027                 throw new ObjectDisposedException(this.GetType().FullName);
1028             }
1029
1030             //
1031             // parameter validation
1032             //
1033             if (asyncResult==null) {
1034                 throw new ArgumentNullException("asyncResult");
1035             }
1036
1037             Socket chkStreamSocket = m_StreamSocket;
1038             if(chkStreamSocket == null) {
1039                 throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
1040             }
1041
1042             try {
1043                 chkStreamSocket.EndSend(asyncResult);
1044             }
1045             catch (Exception exception) {
1046                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
1047                     throw;
1048                     }
1049
1050                 //
1051                 // some sort of error occured on the socket call,
1052                 // set the SocketException as InnerException and throw
1053                 //
1054                 throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
1055             }
1056 #if DEBUG
1057             }
1058 #endif
1059         }
1060
1061
1062         /// <devdoc>
1063         ///    <para>
1064         ///       Performs a [....] Write of an array of buffers.
1065         ///    </para>
1066         /// </devdoc>
1067         internal virtual void MultipleWrite(BufferOffsetSize[] buffers)
1068         {
1069             GlobalLog.ThreadContract(ThreadKinds.Sync, "NetworkStream#" + ValidationHelper.HashString(this) + "::MultipleWrite");
1070
1071             //
1072             // parameter validation
1073             //
1074             if (buffers == null) {
1075                 throw new ArgumentNullException("buffers");
1076             }
1077
1078             Socket chkStreamSocket = m_StreamSocket;
1079             if(chkStreamSocket == null) {
1080                 throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
1081             }
1082
1083             try {
1084
1085                 chkStreamSocket.MultipleSend(
1086                     buffers,
1087                     SocketFlags.None);
1088
1089             }
1090             catch (Exception exception) {
1091                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
1092                     throw;
1093                     }
1094
1095                 //
1096                 // some sort of error occured on the socket call,
1097                 // set the SocketException as InnerException and throw
1098                 //
1099                 throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
1100             }
1101         }
1102
1103
1104         /// <devdoc>
1105         ///    <para>
1106         ///       Starts off an async Write of an array of buffers.
1107         ///    </para>
1108         /// </devdoc>
1109         internal virtual IAsyncResult BeginMultipleWrite(
1110             BufferOffsetSize[] buffers,
1111             AsyncCallback callback,
1112             Object state)
1113         {
1114 #if DEBUG
1115             GlobalLog.ThreadContract(ThreadKinds.Unknown, "NetworkStream#" + ValidationHelper.HashString(this) + "::BeginMultipleWrite");
1116             using (GlobalLog.SetThreadKind(ThreadKinds.Async)) {
1117 #endif
1118
1119             //
1120             // parameter validation
1121             //
1122             if (buffers == null) {
1123                 throw new ArgumentNullException("buffers");
1124             }
1125
1126             Socket chkStreamSocket = m_StreamSocket;
1127             if(chkStreamSocket == null) {
1128                 throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
1129             }
1130
1131             try {
1132
1133                 //
1134                 // call BeginMultipleSend on the Socket.
1135                 //
1136                 IAsyncResult asyncResult =
1137                     chkStreamSocket.BeginMultipleSend(
1138                         buffers,
1139                         SocketFlags.None,
1140                         callback,
1141                         state);
1142
1143                 return asyncResult;
1144             }
1145             catch (Exception exception) {
1146
1147                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
1148                     throw;
1149                     }
1150
1151                 //
1152                 // some sort of error occured on the socket call,
1153                 // set the SocketException as InnerException and throw
1154                 //
1155                 throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
1156             }
1157 #if DEBUG
1158             }
1159 #endif
1160         }
1161
1162
1163         internal virtual IAsyncResult UnsafeBeginMultipleWrite(
1164             BufferOffsetSize[] buffers,
1165             AsyncCallback callback,
1166             Object state)
1167         {
1168 #if DEBUG
1169             GlobalLog.ThreadContract(ThreadKinds.Unknown, "NetworkStream#" + ValidationHelper.HashString(this) + "::BeginMultipleWrite");
1170             using (GlobalLog.SetThreadKind(ThreadKinds.Async)) {
1171 #endif
1172
1173             //
1174             // parameter validation
1175             //
1176             if (buffers == null) {
1177                 throw new ArgumentNullException("buffers");
1178             }
1179
1180             Socket chkStreamSocket = m_StreamSocket;
1181             if(chkStreamSocket == null) {
1182                 throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
1183             }
1184
1185             try {
1186
1187                 //
1188                 // call BeginMultipleSend on the Socket.
1189                 //
1190                 IAsyncResult asyncResult =
1191                     chkStreamSocket.UnsafeBeginMultipleSend(
1192                         buffers,
1193                         SocketFlags.None,
1194                         callback,
1195                         state);
1196
1197                 return asyncResult;
1198             }
1199             catch (Exception exception) {
1200
1201                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
1202                     throw;
1203                     }
1204
1205                 //
1206                 // some sort of error occured on the socket call,
1207                 // set the SocketException as InnerException and throw
1208                 //
1209                 throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
1210             }
1211 #if DEBUG
1212             }
1213 #endif
1214         }
1215
1216
1217         internal virtual void EndMultipleWrite(IAsyncResult asyncResult) {
1218             GlobalLog.ThreadContract(ThreadKinds.Unknown, "NetworkStream#" + ValidationHelper.HashString(this) + "::EndMultipleWrite");
1219
1220             //
1221             // parameter validation
1222             //
1223             if (asyncResult == null) {
1224                 throw new ArgumentNullException("asyncResult");
1225             }
1226
1227             Socket chkStreamSocket = m_StreamSocket;
1228             if(chkStreamSocket == null) {
1229                 throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
1230             }
1231
1232             try {
1233                 chkStreamSocket.EndMultipleSend(asyncResult);
1234             }
1235             catch (Exception exception) {
1236                 if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
1237                     throw;
1238                     }
1239
1240                 //
1241                 // some sort of error occured on the socket call,
1242                 // set the SocketException as InnerException and throw
1243                 //
1244                 throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
1245             }
1246         }
1247
1248         /// <devdoc>
1249         ///    <para>
1250         ///       Flushes data from the stream.  This is meaningless for us, so it does nothing.
1251         ///    </para>
1252         /// </devdoc>
1253         public override void Flush() {
1254         }
1255
1256         public override Task FlushAsync(CancellationToken cancellationToken)
1257         {
1258             return Task.CompletedTask;
1259         }
1260
1261         /// <devdoc>
1262         ///    <para>
1263         ///       Sets the length of the stream. Always throws <see cref='NotSupportedException'/>
1264         ///    </para>
1265         /// </devdoc>
1266         public override void SetLength(long value) {
1267             throw new NotSupportedException(SR.GetString(SR.net_noseek));
1268         }
1269
1270         int m_CurrentReadTimeout = -1;
1271         int m_CurrentWriteTimeout = -1;
1272         internal void SetSocketTimeoutOption(SocketShutdown mode, int timeout, bool silent) {
1273             GlobalLog.Print("NetworkStream#" + ValidationHelper.HashString(this) + "::SetSocketTimeoutOption() mode:" + mode + " silent:" + silent + " timeout:" + timeout + " m_CurrentReadTimeout:" + m_CurrentReadTimeout + " m_CurrentWriteTimeout:" + m_CurrentWriteTimeout);
1274             GlobalLog.ThreadContract(ThreadKinds.Unknown, "NetworkStream#" + ValidationHelper.HashString(this) + "::SetSocketTimeoutOption");
1275
1276             if (timeout < 0) {
1277                 timeout = 0; // -1 becomes 0 for the winsock stack
1278             }
1279
1280             Socket chkStreamSocket = m_StreamSocket;
1281             if (chkStreamSocket==null) {
1282                 return;
1283             }
1284             if (mode==SocketShutdown.Send || mode==SocketShutdown.Both) {
1285                 if (timeout!=m_CurrentWriteTimeout) {
1286                     chkStreamSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, timeout, silent);
1287                     m_CurrentWriteTimeout = timeout;
1288                 }
1289             }
1290             if (mode==SocketShutdown.Receive || mode==SocketShutdown.Both) {
1291                 if (timeout!=m_CurrentReadTimeout) {
1292                     chkStreamSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout, silent);
1293                     m_CurrentReadTimeout = timeout;
1294                 }
1295             }
1296         }
1297
1298 #if TRAVE
1299         [System.Diagnostics.Conditional("TRAVE")]
1300         internal void DebugMembers() {
1301             if (m_StreamSocket != null) {
1302                 GlobalLog.Print("m_StreamSocket:");
1303                 m_StreamSocket.DebugMembers();
1304             }
1305         }
1306 #endif
1307     }
1308 }