You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.3 KiB
180 lines
5.3 KiB
15 years ago
|
// Copyright (c) 2009 Sun Microsystems, Inc.
|
||
|
//
|
||
|
// This program is free software; you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License version 2 as published by
|
||
|
// the Free Software Foundation
|
||
|
//
|
||
|
// There are special exceptions to the terms and conditions of the GPL
|
||
|
// as it is applied to this software. View the full text of the
|
||
|
// exception in file EXCEPTIONS in the directory of this software
|
||
|
// distribution.
|
||
|
//
|
||
|
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
|
||
|
}
|
||
|
|
||
|
}
|