File: MyNetworkStream.cs

package info (click to toggle)
mysql-connector-net 6.4.3-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 6,160 kB
  • ctags: 8,552
  • sloc: cs: 63,689; xml: 7,505; sql: 345; makefile: 50; ansic: 40
file content (182 lines) | stat: -rw-r--r-- 5,601 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Copyright (c) 2009 Sun Microsystems, Inc.
//
// MySQL Connector/NET is licensed under the terms of the GPLv2
// <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most 
// MySQL Connectors. There are special exceptions to the terms and 
// conditions of the GPLv2 as it is applied to this software, see the 
// FLOSS License Exception
// <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
//
// This program is free software; you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published 
// by the Free Software Foundation; version 2 of the License.
//
// This program is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
//
// You should have received a copy of the GNU General Public License along 
// with this program; if not, write to the Free Software Foundation, Inc., 
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA

using System;
using System.Net.Sockets;

internal class MyNetworkStream : NetworkStream
{
    /// <summary>
    /// Wrapper around NetworkStream.
    /// 
    /// MyNetworkStream is equivalent to NetworkStream, except 
    /// 1. It throws TimeoutException if read or write timeout occurs, instead 
    /// of IOException, to match behavior of other streams (named pipe and 
    /// shared memory). This property comes handy in TimedStream.
    ///
    /// 2. It implements workarounds for WSAEWOULDBLOCK errors, that can start 
    /// occuring after stream has times out. For a discussion about the CLR bug,
    /// refer to  http://tinyurl.com/lhgpyf. This error should never occur, as
    /// we're not using asynchronous operations, but apparerntly it does occur
    /// directly after timeout has expired.
    /// The workaround is hinted in the URL above and implemented like this:
    /// For each IO operation, if it throws WSAEWOULDBLOCK, we explicitely set
    /// the socket to Blocking and retry the operation once again.
    /// </summary>
    const int MaxRetryCount = 2;
    Socket socket;

    public MyNetworkStream(Socket socket, bool ownsSocket)
        : base(socket, ownsSocket)
    {
        this.socket = socket;
    }

    bool IsTimeoutException(SocketException e)
    {
#if CF
       return (e.NativeErrorCode == 10060);
#else
        return (e.SocketErrorCode == SocketError.TimedOut);
#endif
    }

    bool IsWouldBlockException(SocketException e)
    {
#if CF
      return (e.NativeErrorCode == 10035);
#else
      return (e.SocketErrorCode == SocketError.WouldBlock);
#endif
    }


    void HandleOrRethrowException(Exception e)
    {
        Exception currentException = e;
        while (currentException != null)
        {
            if (currentException is SocketException)
            {
                SocketException socketException = (SocketException)currentException;
                if (IsWouldBlockException(socketException))
                {
                    // Workaround  for WSAEWOULDBLOCK
                    socket.Blocking= true;
                    // return to give the caller possibility to retry the call
                    return;
                }
                else if (IsTimeoutException(socketException))
                {
                    throw new TimeoutException(socketException.Message, e);
                }

            }
            currentException = currentException.InnerException;
        }
        throw (e);
    }


    public override int Read(byte[] buffer, int offset, int count)
    {
        int retry = 0;
        Exception exception = null;
        do
        {
            try
            {
                return base.Read(buffer, offset, count);
            }
            catch (Exception e)
            {
                exception = e;
                HandleOrRethrowException(e);
            }
        }
        while (++retry < MaxRetryCount);
        throw exception;
    }

    public override int ReadByte()
    {
        int retry = 0;
        Exception exception = null;
        do
        {
            try
            {
                return base.ReadByte();
            }
            catch (Exception e)
            {
                exception = e;
                HandleOrRethrowException(e);
            }
        }
        while (++retry < MaxRetryCount);
        throw exception;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        int retry = 0;
        Exception exception = null;
        do
        {
            try
            {
                base.Write(buffer, offset, count);
                return;
            }
            catch (Exception e)
            {
                exception = e;
                HandleOrRethrowException(e);
            }
        }
        while (++retry < MaxRetryCount);
        throw exception;
    }

    public override void Flush()
    {
        int retry = 0;
        Exception exception = null;
        do
        {
            try
            {
                base.Flush();
                return;
            }
            catch (Exception e)
            {
                exception = e;
                HandleOrRethrowException(e);
            }
        }
        while (++retry < MaxRetryCount);
        throw exception;
    }

}