context: // **********************************************************************
  //
  // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
  //
  // This copy of Ice is licensed to you under the terms described in the
  // ICE_LICENSE file included in this distribution.
  //
  // **********************************************************************
  
  namespace IceInternal
  {
  
      using System;
      using System.ComponentModel;
      using System.Diagnostics;
      using System.Net;
      using System.Net.Sockets;
  
      sealed class TcpTransceiver : Transceiver
      {
          public int initialize()
          {
              if(_state == StateNeedConnect)
              {
                  _state = StateConnectPending;
                  return SocketOperation.Connect;
              }
              else if(_state <= StateConnectPending)
              {
                  try
                  {
                      Network.doFinishConnectAsync(_fd, _writeResult);
                      _writeResult = null;
                      _state = StateConnected;
                      _desc = Network.fdToString(_fd);
                  }
                  catch(Ice.LocalException ex)
                  {
                      if(_traceLevels.network >= 2)
                      {
                          System.Text.StringBuilder s = new System.Text.StringBuilder();
                          s.Append("failed to establish tcp connection\n");
                          s.Append(Network.fdLocalAddressToString(_fd));
                          Debug.Assert(_addr != null);
                          s.Append("\nremote address = " + _addr.ToString() + "\n");
                          s.Append(ex.ToString());
                          _logger.trace(_traceLevels.networkCat, s.ToString());
                      }
                      throw;
                  }
  
                  if(_traceLevels.network >= 1)
                  {
                      string s = "tcp connection established\n" + _desc;
                      _logger.trace(_traceLevels.networkCat, s);
                  }
              }
              Debug.Assert(_state == StateConnected);
              return SocketOperation.None;
          }
  
          public void close()
          {
              //
              // If the transceiver is not connected, its description is simply "not connected",
              // which isn't very helpful.
              //
              if(_state == StateConnected && _traceLevels.network >= 1)
              {
                  string s = "closing tcp connection\n" + ToString();
                  _logger.trace(_traceLevels.networkCat, s);
              }
  
              Debug.Assert(_fd != null);
              try
              {
                  _fd.Close();
              }
              catch(SocketException ex)
              {
                  throw new Ice.SocketException(ex);
              }
              finally
              {
                  _fd = null;
              }
          }
  
          public bool write(Buffer buf)
          {
  #if COMPACT
              //
              // The Compact Framework does not support the use of synchronous socket
              // operations on a non-blocking socket. Returning false here forces the
              // caller to schedule an asynchronous operation.
              //
              return false;
  #else
              int packetSize = buf.b.remaining();
              if(AssemblyUtil.platform_ == AssemblyUtil.Platform.Windows)
              {
                  //
                  // On Windows, limiting the buffer size is important to prevent
                  // poor throughput performance when transferring large amounts of
                  // data. See Microsoft KB article KB823764.
                  //
                  if(_maxSendPacketSize > 0 && packetSize > _maxSendPacketSize / 2)
                  {
                      packetSize = _maxSendPacketSize / 2;
                  }
              }
              else
              {
                  if(_blocking > 0)
                  {
                      return false;
                  }
              }
  
              while(buf.b.hasRemaining())
              {
                  try
                  {
                      Debug.Assert(_fd != null);
  
                      int ret;
                      try
                      {
                          ret = _fd.Send(buf.b.rawBytes(), buf.b.position(), packetSize, SocketFlags.None);
                      }
                      catch(Win32Exception e)
                      {
                          if(Network.wouldBlock(e))
                          {
                              return false;
                          }
                          throw;
                      }
  
                      Debug.Assert(ret > 0);
  
                      if(_traceLevels.network >= 3)
                      {
                          string s = "sent " + ret + " of " + packetSize + " bytes via tcp\n" + ToString();
                          _logger.trace(_traceLevels.networkCat, s);
                      }
  
                      if(_stats != null)
                      {
                          _stats.bytesSent(type(), ret);
                      }
  
                      buf.b.position(buf.b.position() + ret);
                      if(packetSize > buf.b.remaining())
                      {
                          packetSize = buf.b.remaining();
                      }
                  }
                  catch(SocketException ex)
                  {
                      if(Network.connectionLost(ex))
                      {
                          throw new Ice.ConnectionLostException(ex);
                      }
  
                      throw new Ice.SocketException(ex);
                  }
              }
  
              return true; // No more data to send.
  #endif
          }
  
          public bool read(Buffer buf)
          {
  #if COMPACT
              //
              // The .NET Compact Framework does not support the use of synchronous socket
              // operations on a non-blocking socket.
              //
              return false;
  #else
              // COMPILERFIX: Workaround for Mac OS X broken poll(), see Mono bug #470120
              if(AssemblyUtil.osx_)
              {
                  if(_blocking > 0)
                  {
                      return false;
                  }
              }
  
              int remaining = buf.b.remaining();
              int position = buf.b.position();
  
              while(buf.b.hasRemaining())
              {
                  try
                  {
                      Debug.Assert(_fd != null);
  
                      int ret;
                      try
                      {
                          //
                          // Try to receive first. Much of the time, this will work and we
                          // avoid the cost of calling Poll().
                          //
                          ret = _fd.Receive(buf.b.rawBytes(), position, remaining, SocketFlags.None);
                          if(ret == 0)
                          {
                              throw new Ice.ConnectionLostException();
                          }
                      }
                      catch(Win32Exception e)
                      {
                          if(Network.wouldBlock(e))
                          {
                              return false;
                          }
                          throw;
                      }
  
                      Debug.Assert(ret > 0);
  
                      if(_traceLevels.network >= 3)
                      {
                          string s = "received " + ret + " of " + remaining + " bytes via tcp\n" + ToString();
                          _logger.trace(_traceLevels.networkCat, s);
                      }
  
                      if(_stats != null)
                      {
                          _stats.bytesReceived(type(), ret);
                      }
  
                      remaining -= ret;
                      buf.b.position(position += ret);
                  }
                  catch(Win32Exception ex)
                  {
                      //
                      // On Mono, calling shutdownReadWrite() followed by read() causes Socket.Receive() to
                      // raise a socket exception with the "interrupted" error code. We need to check the
                      // socket's Connected status before checking for the interrupted case.
                      //
                      if(!_fd.Connected)
                      {
                          throw new Ice.ConnectionLostException(ex);
                      }
  
                      if(Network.interrupted(ex))
                      {
                          continue;
                      }
  
                      if(Network.connectionLost(ex))
                      {
                          throw new Ice.ConnectionLostException(ex);
                      }
  
                      throw new Ice.SocketException(ex);
                  }
              }
  
              return true;
  #endif
          }
  
          public bool startRead(Buffer buf, AsyncCallback callback, object state)
          {
              Debug.Assert(_fd != null && _readResult == null);
  
              // COMPILERFIX: Workaround for Mac OS X broken poll(), see Mono bug #470120
              if(AssemblyUtil.osx_)
              {
                  if(++_blocking == 1)
                  {
                      Network.setBlock(_fd, true);
                  }
              }
  
              int packetSize = buf.b.remaining();
              if(_maxReceivePacketSize > 0 && packetSize > _maxReceivePacketSize)
              {
                  packetSize = _maxReceivePacketSize;
              }
  
              try
              {
                  _readResult = _fd.BeginReceive(buf.b.rawBytes(), buf.b.position(), packetSize, SocketFlags.None, 
                                                 callback, state);
              }
              catch(Win32Exception ex)
              {
                  if(Network.connectionLost(ex))
                  {
                      throw new Ice.ConnectionLostException(ex);
                  }
  
                  throw new Ice.SocketException(ex);
              }
  
              return _readResult.CompletedSynchronously;
          }
  
          public void finishRead(Buffer buf)
          {
              if(_fd == null) // Transceiver was closed
              {
                  _readResult = null;
                  return;
              }
  
              Debug.Assert(_fd != null && _readResult != null);
  
              try
              {
                  int ret = _fd.EndReceive(_readResult);
                  _readResult = null;
                  if(ret == 0)
                  {
                      throw new Ice.ConnectionLostException();
                  }
  
                  // COMPILERFIX: Workaround for Mac OS X broken poll(), see Mono bug #470120
                  if(AssemblyUtil.osx_)
                  {
                      if(--_blocking == 0)
                      {
                          Network.setBlock(_fd, false);
                      }
                  }
                  Debug.Assert(ret > 0);
  
                  if(_traceLevels.network >= 3)
                  {
  
gt:                     int packetSize = buf.b.remaining();