public Try <bool> Send(byte unitId, List <byte> adu) { if (!_socket.Connected) { return(Try.Failure <bool>(new SocketException((int)SocketError.NotConnected))); } if (_socket.Poll(0, SelectMode.SelectRead)) { /* at this point we assume that there can't be anything to read, * so socket received FINACK some time ago * http://stackoverflow.com/questions/23665917/is-it-possible-to-detect-if-a-socket-is-in-the-close-wait-state/ */ _socket.Close(); return(Try.Failure <bool>(new SocketException((int)SocketError.NotConnected))); } async Task <int> send(ArraySegment <byte> segment) => await _socket.SendAsync(segment, SocketFlags.None); var result = from pdu in Try.Apply(() => new ArraySegment <byte>(MbHelpers.PrependMbapHeader(unitId, _transactionId, adu).ToArray())) from snd in Try.Apply(() => { var sent = send(pdu); sent.Wait(); return(sent.Result); }) select snd == pdu.Count; // TODO: check for exceptions and so on.... return(result); }
public Try <List <byte> > Receive(byte expectedUnitId) { if (!_socket.Connected) { return(Try.Failure <List <byte> >(new SocketException((int)SocketError.NotConnected))); } var buffer = new List <byte>(); async Task receive() { do { var segment = new ArraySegment <byte>(new byte[512]); var received = await _socket.ReceiveAsync(segment, SocketFlags.None); buffer.AddRange(segment.Array.Take(received)); } while (_socket.Available != 0); } bool rectimeout = false; async Task receiveWithTimeout() => await Task.WhenAny(receive(), Task.Delay(_timeout).ContinueWith( t => rectimeout = true)); var result = from rec in Try.Apply(() => receiveWithTimeout().Wait()) from res in Try.Apply(() => { if (rectimeout) { _socket.Close(); throw new SocketException((int)SocketError.TimedOut); } if (buffer.Count == 0) { _socket.Close(); throw new SocketException((int)SocketError.NotConnected); } (var transId, var unitId, var pdu) = MbHelpers.UnwrapMbapHeader(buffer); if (transId != _transactionId) { var message = $"Sent transaction id {_transactionId}, received {transId}. Dropping response."; _logger.Debug(message); throw new Exception(message); } if (unitId != expectedUnitId) { var message = $"Sent unit id {expectedUnitId}, received {unitId}. Dropping response."; _logger.Debug(message); throw new Exception(message); } return(pdu); }) select res; NextTransaction(); return(result); }