示例#1
0
        public int Initialize(ref ArraySegment <byte> readBuffer, IList <ArraySegment <byte> > writeBuffer)
        {
            Debug.Assert(_fd != null);
            if (_state == StateNeedConnect)
            {
                _state = StateConnectPending;
                try
                {
                    if (_sourceAddr != null)
                    {
                        _fd.Bind(_sourceAddr);
                    }
                    _fd.Connect(_addr);
                }
                catch (System.Net.Sockets.SocketException ex)
                {
                    if (Network.WouldBlock(ex))
                    {
                        return(SocketOperation.Connect);
                    }
                    throw new ConnectFailedException(ex);
                }
                catch (System.Exception ex)
                {
                    throw new ConnectFailedException(ex);
                }
                _state = StateConnected;
            }

            Debug.Assert(_state >= StateConnected);
            return(SocketOperation.None);
        }
示例#2
0
        private int WriteData(IList <ArraySegment <byte> > buffer, int offset, int count)
        {
            Debug.Assert(_fd != null);
            if (AssemblyUtil.IsMono)
            {
                //
                // Mono on Android and iOS don't support the use of synchronous socket
                // operations on a non-blocking socket. Returning 0 here forces the caller to schedule
                // an asynchronous operation.
                //
                return(0);
            }

            int packetSize = _maxSendPacketSize;

            if (AssemblyUtil.IsWindows)
            {
                //
                // On Windows, limiting the buffer size is important to prevent
                // poor throughput performances when transferring large amount of
                // data. See Microsoft KB article KB823764.
                //
                if (_maxSendPacketSize > 0 && packetSize > _maxSendPacketSize / 2)
                {
                    packetSize = _maxSendPacketSize / 2;
                }
            }

            int remaining = count - offset;
            int sent      = 0;

            while (remaining - sent > 0)
            {
                try
                {
                    buffer.FillSegments(offset + sent, _sendSegments, Math.Min(remaining - sent, packetSize));
                    int ret = _fd.Send(_sendSegments, SocketFlags.None);
                    _sendSegments.Clear();
                    Debug.Assert(ret > 0);
                    sent += ret;
                }
                catch (SocketException ex)
                {
                    if (Network.WouldBlock(ex))
                    {
                        return(sent);
                    }
                    else if (Network.ConnectionLost(ex))
                    {
                        throw new ConnectionLostException(ex);
                    }
                    throw new TransportException(ex);
                }
            }
            return(sent);
        }
示例#3
0
        private int ReadData(ArraySegment <byte> buffer, int offset)
        {
            Debug.Assert(_fd != null);
            if (AssemblyUtil.IsMono)
            {
                //
                // Mono on Android and iOS don't support the use of synchronous socket
                // operations on a non-blocking socket. Returning 0 here forces the caller to schedule
                // an asynchronous operation.
                //
                return(0);
            }

            int bytesTransferred = 0;
            int bufferOffset     = buffer.Offset + offset;

            while (buffer.Count - (offset + bytesTransferred) > 0)
            {
                try
                {
                    int ret = _fd.Receive(buffer.Array, bufferOffset + bytesTransferred,
                                          GetRecvPacketSize(buffer.Count - (offset + bytesTransferred)),
                                          SocketFlags.None);
                    if (ret == 0)
                    {
                        throw new ConnectionLostException();
                    }
                    bytesTransferred += ret;
                }
                catch (SocketException ex)
                {
                    if (Network.WouldBlock(ex))
                    {
                        return(bytesTransferred);
                    }
                    else if (Network.Interrupted(ex))
                    {
                        continue;
                    }
                    else if (Network.ConnectionLost(ex))
                    {
                        throw new ConnectionLostException(ex);
                    }

                    throw new TransportException(ex);
                }
            }
            return(bytesTransferred);
        }
示例#4
0
        public int Read(ref ArraySegment <byte> buffer, ref int offset)
        {
            if (buffer.Count - offset == 0)
            {
                return(SocketOperation.None);
            }

            Debug.Assert(offset == 0);
            Debug.Assert(_fd != null);

            int packetSize = Math.Min(MaxPacketSize, _rcvSize - UdpOverhead);

            Debug.Assert(buffer.Count == 0);
            buffer = new byte[packetSize];

            int ret;

            while (true)
            {
                try
                {
                    EndPoint?peerAddr = _peerAddr;
                    if (peerAddr == null)
                    {
                        if (_addr.AddressFamily == AddressFamily.InterNetwork)
                        {
                            peerAddr = new IPEndPoint(IPAddress.Any, 0);
                        }
                        else
                        {
                            Debug.Assert(_addr.AddressFamily == AddressFamily.InterNetworkV6);
                            peerAddr = new IPEndPoint(IPAddress.IPv6Any, 0);
                        }
                    }

                    // TODO: Workaround for https://github.com/dotnet/corefx/issues/31182
                    if (_state == StateConnected ||
                        (AssemblyUtil.IsMacOS && _fd.AddressFamily == AddressFamily.InterNetworkV6 && _fd.DualMode))
                    {
                        ret = _fd.Receive(buffer.Array, 0, packetSize, SocketFlags.None);
                    }
                    else
                    {
                        ret       = _fd.ReceiveFrom(buffer.Array, 0, packetSize, SocketFlags.None, ref peerAddr);
                        _peerAddr = (IPEndPoint)peerAddr;
                    }
                    break;
                }
                catch (System.Net.Sockets.SocketException e)
                {
                    if (Network.RecvTruncated(e))
                    {
                        // The message was truncated and the whole buffer is filled. We ignore
                        // this error here, it will be detected at the connection level when
                        // the Ice message size is checked against the buffer size.
                        ret = buffer.Count;
                        break;
                    }

                    if (Network.Interrupted(e))
                    {
                        continue;
                    }

                    if (Network.WouldBlock(e))
                    {
                        return(SocketOperation.Read);
                    }

                    if (Network.ConnectionLost(e))
                    {
                        throw new ConnectionLostException();
                    }
                    else
                    {
                        throw new TransportException(e);
                    }
                }
            }

            if (ret == 0)
            {
                throw new ConnectionLostException();
            }

            if (_state == StateNeedConnect)
            {
                Debug.Assert(_incoming);

                //
                // If we must connect, then we connect to the first peer that sends us a packet.
                //
                Debug.Assert(_peerAddr != null);
                bool connected = Network.DoConnect(_fd, _peerAddr, null);
                Debug.Assert(connected);
                _state = StateConnected; // We're connected now

                if (_communicator.TraceLevels.Network >= 1)
                {
                    _communicator.Logger.Trace(_communicator.TraceLevels.NetworkCat,
                                               $"connected {Transport} socket\n{this}");
                }
            }

            buffer = buffer.Slice(0, ret);
            offset = ret;
            return(SocketOperation.None);
        }
示例#5
0
        public int Write(IList <ArraySegment <byte> > buffer, ref int offset)
        {
            int count     = buffer.GetByteCount();
            int remaining = count - offset;

            if (remaining == 0)
            {
                return(SocketOperation.None);
            }

            Debug.Assert(_fd != null && _state >= StateConnected);

            // The caller is supposed to check the send size before by calling checkSendSize
            Debug.Assert(Math.Min(MaxPacketSize, _sndSize - UdpOverhead) >= count);

            int ret;

            while (true)
            {
                try
                {
                    if (_state == StateConnected)
                    {
                        ret = _fd.Send(buffer, SocketFlags.None);
                    }
                    else
                    {
                        if (_peerAddr == null)
                        {
                            throw new TransportException("cannot send datagram to undefined peer");
                        }

                        ArraySegment <byte> data = buffer.GetSegment(0, count);
                        ret = _fd.SendTo(data.Array, 0, data.Count, SocketFlags.None, _peerAddr);
                    }
                    Debug.Assert(ret == count);
                    offset += ret;
                    break;
                }
                catch (System.Net.Sockets.SocketException ex)
                {
                    if (Network.Interrupted(ex))
                    {
                        continue;
                    }

                    if (Network.WouldBlock(ex))
                    {
                        return(SocketOperation.Write);
                    }

                    if (Network.ConnectionLost(ex))
                    {
                        throw new ConnectionLostException(ex);
                    }
                    else
                    {
                        throw new TransportException(ex);
                    }
                }
            }
            return(SocketOperation.None);
        }