public static async Task <StunMessage> Parse(Stream stream) { var header = new byte[20]; await stream.ReadAsync(header, 0, 20); MessageMethod method = ParseMethod(header[0], header[1]); MessageClass @class = ParseClass(header[0], header[1]); var length = new byte[2]; System.Array.Copy(header, 2, length, 0, 2); var transactionId = new byte[12]; System.Array.Copy(header, 8, transactionId, 0, 12); var body = new byte[length.ToUShort()]; await stream.ReadAsync(body, 0, body.Length); IEnumerable <Attribute> attributes = ParseAttributes( body, transactionId ); StunMessage rv = null; switch (@class) { case MessageClass.SuccessResponse: switch (method) { case MessageMethod.Allocate: rv = new AllocateSuccessResponse(); break; case MessageMethod.Connect: rv = new ConnectSuccessResponse(); break; case MessageMethod.ConnectionBind: rv = new ConnectionBindSuccessResponse(); break; case MessageMethod.Binding: rv = new BindingSuccessResponse(); break; case MessageMethod.CreatePermission: rv = new CreatePermissionSuccessResponse(); break; case MessageMethod.Refresh: rv = new RefreshSuccessResponse(); break; } break; case MessageClass.ErrorResponse: switch (method) { case MessageMethod.Allocate: rv = new AllocateErrorResponse(); break; case MessageMethod.CreatePermission: rv = new CreatePermissionErrorResponse(); break; case MessageMethod.Refresh: rv = new RefreshErrorResponse(); break; } break; case MessageClass.Indication: switch (method) { case MessageMethod.ConnectionAttempt: rv = new ConnectionAttempt(); break; } break; } if (rv != null) { rv.TransactionId = transactionId; rv.Attributes = attributes; } return(rv); }