private async Task OpenSocketAsync() { _wtoken = new CancellationTokenSource(); if (string.IsNullOrEmpty(Hostname)) { throw new ArgumentNullException(nameof(Hostname)); } if (Port <= 0 || Port > 65535) { throw new ArgumentOutOfRangeException(nameof(Port)); } if (!string.IsNullOrEmpty(Proxy?.ProxyHostname)) { var proxy = new SocksTcpClient(Proxy); _tcpClient = await proxy.ConnectAsync(Hostname, Port); } else { _tcpClient = new TcpClient(); } try { // try connecting State = IrcConnectionState.Connecting; var connectTask = _tcpClient.ConnectAsync(Hostname, Port); var connectTimeoutTask = Task.Run(async() => await Task.Delay(5000, _wtoken.Token).ConfigureAwait(false)); var firstCompletedTask = await Task.WhenAny(connectTask, connectTimeoutTask).ConfigureAwait(false); if (firstCompletedTask == connectTimeoutTask) { State = IrcConnectionState.Disconnected; } else { await connectTask; // we await the finished task so we can throw the exception await SocketEntryAsync(_wtoken.Token).ConfigureAwait(false); await Socket_OnConnected(); } } catch (SocketException e) { OnConnectionError(new ErrorEventArgs(e)); } catch (SocksException e) { OnConnectionError(new ErrorEventArgs(e)); } catch (IOException e) { OnConnectionError(new ErrorEventArgs(e)); } }
private async Task SocketLoopAsync(CancellationToken token) { if (!string.IsNullOrEmpty(_proxy?.ProxyHostname)) { var proxy = new SocksTcpClient(_proxy); _tcpClient = await proxy.ConnectAsync(_server, _port, token); } else { _tcpClient = new TcpClient(); using (token.Register(() => _tcpClient.Dispose())) { await _tcpClient.ConnectAsync(_server, _port); } token.ThrowIfCancellationRequested(); } Stream stream = _tcpClient.GetStream(); if (_isSecure) { // Just accept all server certs for now; we'll take advantage of the encryption // but not the authentication unless users ask for it. var sslStream = new SslStream(stream, true, (sender, cert, chain, sslPolicyErrors) => true); await sslStream.AuthenticateAsClientAsync(_server); stream = sslStream; } Dispatch(OnConnected); async Task ReadLoopAsync() { byte[] readBuffer = new byte[512]; var gotCR = false; var input = new List <byte>(512); while (_tcpClient.Connected) { var count = await stream.ReadAsync(readBuffer, 0, readBuffer.Length, token); if (count == 0) { _tcpClient.Dispose(); } else { for (var i = 0; i < count; i++) { switch (readBuffer[i]) { case 0xa: if (gotCR) { var incoming = IrcMessage.Parse(Encoding.UTF8.GetString(input.ToArray())); Dispatch(OnMessageReceived, incoming); input.Clear(); } break; case 0xd: break; default: input.Add(readBuffer[i]); break; } gotCR = readBuffer[i] == 0xd; } } } }; Task WriteLoopAsync() { return(Task.Run(async() => { byte[] writeBuffer = new byte[Encoding.UTF8.GetMaxByteCount(512)]; while (_tcpClient.Connected) { var outgoing = _writeQueue.Take(token); var output = outgoing.ToString(); int count = Encoding.UTF8.GetBytes(output, 0, output.Length, writeBuffer, 0); count = Math.Min(510, count); writeBuffer[count] = 0xd; writeBuffer[count + 1] = 0xa; await stream.WriteAsync(writeBuffer, 0, count + 2); Dispatch(OnMessageSent, outgoing); } }, token)); }; async Task HeartbeatLoopAsync() { while (_tcpClient.Connected) { await Task.Delay(HeartbeatInterval, token); Dispatch(OnHeartbeat); } }; try { await Task.WhenAll(ReadLoopAsync(), WriteLoopAsync(), HeartbeatLoopAsync()); } finally { Dispatch(OnDisconnected); } }