57a54e084e5dca43303c064dee01417fa59739d9
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / ConnectionModeReader.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Diagnostics;
7     using System.Runtime;
8     using System.ServiceModel;
9     using System.Threading;
10
11     delegate void ConnectionModeCallback(ConnectionModeReader connectionModeReader);
12
13     sealed class ConnectionModeReader : InitialServerConnectionReader
14     {
15         Exception readException;
16         ServerModeDecoder decoder;
17         byte[] buffer;
18         int offset;
19         int size;
20         ConnectionModeCallback callback;
21         static WaitCallback readCallback;
22         TimeoutHelper receiveTimeoutHelper;
23
24         public ConnectionModeReader(IConnection connection, ConnectionModeCallback callback, ConnectionClosedCallback closedCallback)
25             : base(connection, closedCallback)
26         {
27             this.callback = callback;
28         }
29
30         public int BufferOffset
31         {
32             get { return offset; }
33         }
34
35         public int BufferSize
36         {
37             get { return size; }
38         }
39
40         public long StreamPosition
41         {
42             get { return decoder.StreamPosition; }
43         }
44
45         public TimeSpan GetRemainingTimeout()
46         {
47             return this.receiveTimeoutHelper.RemainingTime();
48         }
49
50         void Complete(Exception e)
51         {
52             // exception will be logged by the caller
53             readException = e;
54             Complete();
55         }
56
57         void Complete()
58         {
59             callback(this);
60         }
61
62         bool ContinueReading()
63         {
64             for (;;)
65             {
66                 if (size == 0)
67                 {
68                     if (readCallback == null)
69                     {
70                         readCallback = new WaitCallback(ReadCallback);
71                     }
72
73                     if (Connection.BeginRead(0, Connection.AsyncReadBufferSize, GetRemainingTimeout(),
74                         readCallback, this) == AsyncCompletionResult.Queued)
75                     {
76                         break;
77                     }
78                     if (!GetReadResult()) // we're at EOF, bail
79                     {
80                         return false;
81                     }
82                 }
83
84                 for (;;)
85                 {
86                     int bytesDecoded;
87                     try
88                     {
89                         bytesDecoded = decoder.Decode(buffer, offset, size);
90                     }
91                     catch (CommunicationException e)
92                     {
93                         // see if we need to send back a framing fault
94                         string framingFault;
95                         if (FramingEncodingString.TryGetFaultString(e, out framingFault))
96                         {
97                             byte[] drainBuffer = new byte[128];
98                             InitialServerConnectionReader.SendFault(
99                                 Connection, framingFault, drainBuffer, GetRemainingTimeout(),
100                                 MaxViaSize + MaxContentTypeSize);
101                             base.Close(GetRemainingTimeout());
102                         }
103                         throw;
104                     }
105
106                     if (bytesDecoded > 0)
107                     {
108                         offset += bytesDecoded;
109                         size -= bytesDecoded;
110                     }
111                     if (decoder.CurrentState == ServerModeDecoder.State.Done)
112                     {
113                         return true;
114                     }
115                     if (size == 0)
116                     {
117                         break;
118                     }
119                 }
120             }
121
122             return false;
123         }
124
125         static void ReadCallback(object state)
126         {
127             ConnectionModeReader reader = (ConnectionModeReader)state;
128             bool completeSelf = false;
129             Exception completionException = null;
130             try
131             {
132                 if (reader.GetReadResult())
133                 {
134                     completeSelf = reader.ContinueReading();
135                 }
136             }
137 #pragma warning suppress 56500 // Microsoft, transferring exception to caller
138             catch (Exception e)
139             {
140                 if (Fx.IsFatal(e))
141                 {
142                     throw;
143                 }
144
145                 completeSelf = true;
146                 completionException = e;
147             }
148
149             if (completeSelf)
150             {
151                 reader.Complete(completionException);
152             }
153         }
154
155         bool GetReadResult()
156         {
157             offset = 0;
158             size = Connection.EndRead();
159             if (size == 0)
160             {
161                 if (this.decoder.StreamPosition == 0) // client timed out a cached connection
162                 {
163                     base.Close(GetRemainingTimeout());
164                     return false;
165                 }
166                 else
167                 {
168                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(decoder.CreatePrematureEOFException());
169                 }
170             }
171
172             // restore ExceptionEventType to Error after the initial read for cached connections
173             Connection.ExceptionEventType = TraceEventType.Error;
174
175             if (buffer == null)
176             {
177                 buffer = Connection.AsyncReadBuffer;
178             }
179
180             return true;
181         }
182
183         public FramingMode GetConnectionMode()
184         {
185             if (readException != null)
186             {
187                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(readException, Connection.ExceptionEventType);
188             }
189
190             return decoder.Mode;
191         }
192
193         public void StartReading(TimeSpan receiveTimeout, Action connectionDequeuedCallback)
194         {
195             this.decoder = new ServerModeDecoder();
196             this.receiveTimeoutHelper = new TimeoutHelper(receiveTimeout);
197             this.ConnectionDequeuedCallback = connectionDequeuedCallback;
198             bool completeSelf = false;
199             Exception completionException = null;
200             try
201             {
202                 completeSelf = ContinueReading();
203             }
204 #pragma warning suppress 56500 // Microsoft, transferring exception to caller
205             catch (Exception e)
206             {
207                 if (Fx.IsFatal(e))
208                 {
209                     throw;
210                 }
211
212                 completeSelf = true;
213                 completionException = e;
214             }
215
216             if (completeSelf)
217             {
218                 Complete(completionException);
219             }
220         }
221     }
222 }