Beispiel #1
0
        private async Task DoSendAsync(PayloadData payload, CancellationToken cancellationToken)
        {
            var       bytesSent      = 0;
            var       data           = payload.ArraySegment;
            const int maxBytesToSend = 16777215;
            int       bytesToSend;

            do
            {
                // break payload into packets of at most (2^24)-1 bytes
                bytesToSend = Math.Min(data.Count - bytesSent, maxBytesToSend);

                // write four-byte packet header; https://dev.mysql.com/doc/internals/en/mysql-packet.html
                SerializationUtility.WriteUInt32((uint)bytesToSend, m_buffer, 0, 3);
                m_buffer[3] = (byte)m_sequenceId;
                m_sequenceId++;

                if (bytesToSend <= m_buffer.Length - 4)
                {
                    Buffer.BlockCopy(data.Array, data.Offset, m_buffer, 4, bytesToSend);
                    m_socketAwaitable.EventArgs.SetBuffer(0, bytesToSend + 4);
                    await m_socket.SendAsync(m_socketAwaitable);
                }
                else
                {
                    m_socketAwaitable.EventArgs.SetBuffer(null, 0, 0);
                    m_socketAwaitable.EventArgs.BufferList = new[] { new ArraySegment <byte>(m_buffer, 0, 4), data };
                    await m_socket.SendAsync(m_socketAwaitable);

                    m_socketAwaitable.EventArgs.BufferList = null;
                    m_socketAwaitable.EventArgs.SetBuffer(m_buffer, 0, 0);
                }

                bytesSent += bytesToSend;
            } while (bytesToSend == maxBytesToSend);
        }
Beispiel #2
0
        private async Task <bool> OpenTcpSocketAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            foreach (var hostname in cs.Hostnames)
            {
                IPAddress[] ipAddresses;
                try
                {
#if NETSTANDARD1_3
// Dns.GetHostAddresses isn't available until netstandard 2.0: https://github.com/dotnet/corefx/pull/11950
                    ipAddresses = await Dns.GetHostAddressesAsync(hostname).ConfigureAwait(false);
#else
                    if (ioBehavior == IOBehavior.Asynchronous)
                    {
                        ipAddresses = await Dns.GetHostAddressesAsync(hostname).ConfigureAwait(false);
                    }
                    else
                    {
                        ipAddresses = Dns.GetHostAddresses(hostname);
                    }
#endif
                }
                catch (SocketException)
                {
                    // name couldn't be resolved
                    continue;
                }

                // need to try IP Addresses one at a time: https://github.com/dotnet/corefx/issues/5829
                foreach (var ipAddress in ipAddresses)
                {
                    TcpClient tcpClient = null;
                    try
                    {
                        tcpClient = new TcpClient(ipAddress.AddressFamily);

                        using (cancellationToken.Register(() => tcpClient?.Client?.Dispose()))
                        {
                            try
                            {
                                if (ioBehavior == IOBehavior.Asynchronous)
                                {
                                    await tcpClient.ConnectAsync(ipAddress, cs.Port).ConfigureAwait(false);
                                }
                                else
                                {
#if NETSTANDARD1_3
                                    await tcpClient.ConnectAsync(ipAddress, cs.Port).ConfigureAwait(false);
#else
                                    if (Utility.IsWindows())
                                    {
                                        tcpClient.Connect(ipAddress, cs.Port);
                                    }
                                    else
                                    {
                                        // non-windows platforms block on synchronous connect, use send/receive timeouts: https://github.com/dotnet/corefx/issues/20954
                                        var originalSendTimeout    = tcpClient.Client.SendTimeout;
                                        var originalReceiveTimeout = tcpClient.Client.ReceiveTimeout;
                                        tcpClient.Client.SendTimeout    = cs.ConnectionTimeoutMilliseconds;
                                        tcpClient.Client.ReceiveTimeout = cs.ConnectionTimeoutMilliseconds;
                                        tcpClient.Connect(ipAddress, cs.Port);
                                        tcpClient.Client.SendTimeout    = originalSendTimeout;
                                        tcpClient.Client.ReceiveTimeout = originalReceiveTimeout;
                                    }
#endif
                                }
                            }
                            catch (ObjectDisposedException ex) when(cancellationToken.IsCancellationRequested)
                            {
                                throw new MySqlException("Connect Timeout expired.", ex);
                            }
                        }
                    }
                    catch (SocketException)
                    {
                        tcpClient?.Client?.Dispose();
                        continue;
                    }

                    m_hostname      = hostname;
                    m_tcpClient     = tcpClient;
                    m_socket        = m_tcpClient.Client;
                    m_networkStream = m_tcpClient.GetStream();
                    SerializationUtility.SetKeepalive(m_socket, cs.Keepalive);
                    lock (m_lock)
                        m_state = State.Connected;
                    return(true);
                }
            }
            return(false);
        }
Beispiel #3
0
        private async Task <PayloadData> DoReceiveAsync2(CancellationToken cancellationToken, bool optional = false)
        {
            if (m_end - m_offset < 4)
            {
                if (m_end - m_offset > 0)
                {
                    Buffer.BlockCopy(m_buffer, m_offset, m_buffer, 0, m_end - m_offset);
                }
                m_end   -= m_offset;
                m_offset = 0;
            }

            // read packet header
            int offset = m_end;
            int count  = m_buffer.Length - m_end;

            while (m_end - m_offset < 4)
            {
                m_socketAwaitable.EventArgs.SetBuffer(offset, count);
                await m_socket.ReceiveAsync(m_socketAwaitable);

                int bytesRead = m_socketAwaitable.EventArgs.BytesTransferred;
                if (bytesRead <= 0)
                {
                    if (optional)
                    {
                        return(null);
                    }
                    throw new EndOfStreamException();
                }
                offset += bytesRead;
                m_end  += bytesRead;
                count  -= bytesRead;
            }

            // decode packet header
            int payloadLength = (int)SerializationUtility.ReadUInt32(m_buffer, m_offset, 3);

            if (m_buffer[m_offset + 3] != (byte)(m_sequenceId & 0xFF))
            {
                if (optional)
                {
                    return(null);
                }
                throw new InvalidOperationException("Packet received out-of-order. Expected {0}; got {1}.".FormatInvariant(m_sequenceId & 0xFF, m_buffer[3]));
            }
            m_sequenceId++;
            m_offset += 4;

            if (m_end - m_offset >= payloadLength)
            {
                offset    = m_offset;
                m_offset += payloadLength;
                return(new PayloadData(new ArraySegment <byte>(m_buffer, offset, payloadLength)));
            }

            // allocate a larger buffer if necessary
            var readData = m_buffer;

            if (payloadLength > m_buffer.Length)
            {
                readData = new byte[payloadLength];
                m_socketAwaitable.EventArgs.SetBuffer(readData, 0, 0);
            }
            Buffer.BlockCopy(m_buffer, m_offset, readData, 0, m_end - m_offset);
            m_end   -= m_offset;
            m_offset = 0;

            // read payload
            offset = m_end;
            count  = readData.Length - m_end;
            while (m_end < payloadLength)
            {
                m_socketAwaitable.EventArgs.SetBuffer(offset, count);
                await m_socket.ReceiveAsync(m_socketAwaitable);

                int bytesRead = m_socketAwaitable.EventArgs.BytesTransferred;
                if (bytesRead <= 0)
                {
                    throw new EndOfStreamException();
                }
                offset += bytesRead;
                m_end  += bytesRead;
                count  -= bytesRead;
            }

            // switch back to original buffer if a larger one was allocated
            if (payloadLength > m_buffer.Length)
            {
                m_socketAwaitable.EventArgs.SetBuffer(m_buffer, 0, 0);
                m_end = 0;
            }

            if (payloadLength <= m_buffer.Length)
            {
                m_offset = payloadLength;
            }

            return(new PayloadData(new ArraySegment <byte>(readData, 0, payloadLength)));
        }