Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 134 additions & 42 deletions TDSClient/TDSClient/TDS/Client/TDSSQLTestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@
namespace TDSClient.TDS.Client
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Threading;
using TDSClient.TDS.Comms;
using TDSClient.TDS.Header;
using TDSClient.TDS.Login7;
using TDSClient.TDS.PreLogin;
using TDSClient.TDS.Query;
using TDSClient.TDS.Tokens;
using TDSClient.TDS.Tokens.Cols;
using TDSClient.TDS.Tranasction.Header.Headers;
using TDSClient.TDS.Tranasction.Headers;
using TDSClient.TDS.Utilities;

/// <summary>
Expand All @@ -40,7 +46,7 @@ public class TDSSQLTestClient
/// <param name="password">User password</param>
/// <param name="database">Database to connect to</param>
/// <param name="encryptionProtocol">Encryption Protocol</param>
public TDSSQLTestClient(string server, int port, string userID, string password, string database, SslProtocols encryptionProtocol = SslProtocols.Tls12)
public TDSSQLTestClient(string server, int port, string userID, string password, string database, SslProtocols encryptionProtocol = SslProtocols.Tls12, TDSLogin7TypeFlagsReadOnlyIntent readOnlyIntent = TDSLogin7TypeFlagsReadOnlyIntent.Off)
{
if (string.IsNullOrEmpty(server) || string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(database))
{
Expand All @@ -55,6 +61,7 @@ public TDSSQLTestClient(string server, int port, string userID, string password,
this.Password = password;
this.Database = database;
this.EncryptionProtocol = encryptionProtocol;
this.ReadOnlyIntent = readOnlyIntent;
this.connectionAttempt = 0;

LoggingUtilities.WriteLog($" Instantiating TDSSQLTestClient with the following parameters:");
Expand Down Expand Up @@ -110,6 +117,11 @@ public TDSSQLTestClient(string server, int port, string userID, string password,
/// </summary>
public SslProtocols EncryptionProtocol { get; set; }

/// <summary>
/// Gets or sets the ReadOnly Intent Policy.
/// </summary>
public TDSLogin7TypeFlagsReadOnlyIntent ReadOnlyIntent {get; set;}

/// <summary>
/// Sends PreLogin message to the server.
/// </summary>
Expand Down Expand Up @@ -163,7 +175,7 @@ public void SendLogin7()

tdsMessageBody.TypeFlags.OLEDB = TDSLogin7TypeFlagsOLEDB.On;
tdsMessageBody.TypeFlags.SQLType = TDSLogin7TypeFlagsSQLType.DFLT;
tdsMessageBody.TypeFlags.ReadOnlyIntent = TDSLogin7TypeFlagsReadOnlyIntent.On;
tdsMessageBody.TypeFlags.ReadOnlyIntent = this.ReadOnlyIntent;

this.TdsCommunicator.SendTDSMessage(tdsMessageBody);

Expand Down Expand Up @@ -212,46 +224,7 @@ public void ReceiveLogin7Response()
{
foreach (var token in response.Tokens)
{
if (token is TDSEnvChangeToken)
{
var envChangeToken = token as TDSEnvChangeToken;
if (envChangeToken.Type == Tokens.EnvChange.TDSEnvChangeType.Routing)
{
LoggingUtilities.WriteLog($" Client received EnvChange routing token, client is being routed.");
this.Server = envChangeToken.Values["AlternateServer"];
this.Port = int.Parse(envChangeToken.Values["ProtocolProperty"]);
this.reconnect = true;
LoggingUtilities.WriteLog($" Redirect to {this.Server}:{this.Port}", writeToSummaryLog: true, writeToVerboseLog: false);
}
}
else if (token is TDSErrorToken)
{
var errorToken = token as TDSErrorToken;
LoggingUtilities.WriteLog($" Client received Error token, Number: {errorToken.Number}, State: {errorToken.State}", writeToSummaryLog: true); ;
LoggingUtilities.WriteLog($" MsgText: {errorToken.MsgText}");
LoggingUtilities.WriteLog($" Class: {errorToken.Class}");
LoggingUtilities.WriteLog($" ServerName: {errorToken.ServerName}");
LoggingUtilities.WriteLog($" ProcName: {errorToken.ProcName}");
LoggingUtilities.WriteLog($" LineNumber: {errorToken.LineNumber}");

if (errorToken.Number == 18456)
{
throw new Exception("Login failure.");
}
}
else if (token is TDSInfoToken)
{
var infoToken = token as TDSInfoToken;
LoggingUtilities.WriteLog($" Client received Info token:");

LoggingUtilities.WriteLog($" Number: {infoToken.Number}");
LoggingUtilities.WriteLog($" State: {infoToken.State}");
LoggingUtilities.WriteLog($" Class: {infoToken.Class}");
LoggingUtilities.WriteLog($" MsgText: {infoToken.MsgText}");
LoggingUtilities.WriteLog($" ServerName: {infoToken.ServerName}");
LoggingUtilities.WriteLog($" ProcName: {infoToken.ProcName}");
LoggingUtilities.WriteLog($" LineNumber: {infoToken.LineNumber}");
}
PrintTdsToken(token);
}
}
else
Expand All @@ -262,6 +235,72 @@ public void ReceiveLogin7Response()
LoggingUtilities.WriteLog($" Login7 response received.");
}

private void PrintTdsToken(TDSToken token)
{
if (token is TDSEnvChangeToken)
{
var envChangeToken = token as TDSEnvChangeToken;
if (envChangeToken.Type == Tokens.EnvChange.TDSEnvChangeType.Routing)
{
LoggingUtilities.WriteLog($" Client received EnvChange routing token, client is being routed.");
this.Server = envChangeToken.Values["AlternateServer"];
this.Port = int.Parse(envChangeToken.Values["ProtocolProperty"]);
this.reconnect = true;
LoggingUtilities.WriteLog($" Redirect to {this.Server}:{this.Port}", writeToSummaryLog: true, writeToVerboseLog: false);
}
}
else if (token is TDSErrorToken)
{
var errorToken = token as TDSErrorToken;
LoggingUtilities.WriteLog($" Client received Error token, Number: {errorToken.Number}, State: {errorToken.State}", writeToSummaryLog: true); ;
LoggingUtilities.WriteLog($" MsgText: {errorToken.MsgText}");
LoggingUtilities.WriteLog($" Class: {errorToken.Class}");
LoggingUtilities.WriteLog($" ServerName: {errorToken.ServerName}");
LoggingUtilities.WriteLog($" ProcName: {errorToken.ProcName}");
LoggingUtilities.WriteLog($" LineNumber: {errorToken.LineNumber}");

if (errorToken.Number == 18456)
{
throw new Exception("Login failure.");
}
}
else if (token is TDSInfoToken)
{
var infoToken = token as TDSInfoToken;
LoggingUtilities.WriteLog($" Client received Info token:");

LoggingUtilities.WriteLog($" Number: {infoToken.Number}");
LoggingUtilities.WriteLog($" State: {infoToken.State}");
LoggingUtilities.WriteLog($" Class: {infoToken.Class}");
LoggingUtilities.WriteLog($" MsgText: {infoToken.MsgText}");
LoggingUtilities.WriteLog($" ServerName: {infoToken.ServerName}");
LoggingUtilities.WriteLog($" ProcName: {infoToken.ProcName}");
LoggingUtilities.WriteLog($" LineNumber: {infoToken.LineNumber}");
}
else if (token is TDSColMetadataToken colMetadataToken)
{
LoggingUtilities.WriteLog($" Client Column Metadata Info token:");

LoggingUtilities.WriteLog($" Columns: {colMetadataToken.Count}");
for (int i = 0; i < colMetadataToken.Metadata.Length; i++)
{
var metadata = colMetadataToken.Metadata[i];
LoggingUtilities.WriteLog($" Index: {i}");
LoggingUtilities.WriteLog($" Name: {metadata.ColumnName}");
LoggingUtilities.WriteLog($" Type: {metadata.Type.Type}");
LoggingUtilities.WriteLog("");
}
}
else if (token is TDSRowToken rowToken)
{
LoggingUtilities.WriteLog($" Client Row data token:");
for(int i = 0; i < rowToken.Values.Length; i++)
{
LoggingUtilities.WriteLog($" Row [{i}]: {rowToken.Values[i]?.ToString() ?? "NUll"}");
}
}
}

/// <summary>
/// Connect to the server.
/// </summary>
Expand Down Expand Up @@ -332,6 +371,59 @@ public void Connect()
}
}

public int queryCount = 0;
public (string[], object[][]) Query(string query)
{
var id = Interlocked.Increment(ref queryCount);
string[] colNames = Array.Empty<string>();
List<object[]> result = new List<object[]>();
try
{
var request = new TDSSqlBatchPacketData(query);
var header = new SqlHeaderPacketData(new TransactionDescriptorHeaderData((uint)id));
request.AllHeaders.Headers.Add(header);

TdsCommunicator.SendTDSMessage(request);

if (this.TdsCommunicator.ReceiveTDSMessage() is TDSTokenStreamPacketData response)
{
foreach (var token in response.Tokens)
{
PrintTdsToken(token);

if (token is TDSColMetadataToken colMetadataToken)
{
colNames = new string[colMetadataToken.Count];
for (int i = 0; i < colMetadataToken.Metadata.Length; i++)
{
var metadata = colMetadataToken.Metadata[i];
colNames[i] = metadata.ColumnName;
}
}
else if (token is TDSRowToken rowToken)
{
LoggingUtilities.WriteLog($" Client Row data token:");
result.Add(rowToken.Values);
}
}
}
else
{
throw new InvalidOperationException();
}
}
catch(Exception ex)
{
LoggingUtilities.WriteLog($"Exception:");
LoggingUtilities.WriteLog($"{ex.Message}");
if (ex.InnerException != null)
{
LoggingUtilities.WriteLog($"InnerException: {ex.InnerException.Message}");
}
}
return (colNames, result.ToArray());
}

private void MeasureDNSResolutionTime()
{
try
Expand Down
38 changes: 35 additions & 3 deletions TDSClient/TDSClient/TDS/Comms/TDSCommunicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace TDSClient.TDS.Comms
using TDSClient.TDS.Interfaces;
using TDSClient.TDS.Login7;
using TDSClient.TDS.PreLogin;
using TDSClient.TDS.Query;
using TDSClient.TDS.Tokens;
using TDSClient.TDS.Utilities;
using static System.Net.Mime.MediaTypeNames;
Expand Down Expand Up @@ -221,9 +222,28 @@ public ITDSPacketData ReceiveTDSMessage()
}

case TDSCommunicatorState.SentLogin7RecordWithCompleteAuthToken:
{
var tokenStream = new TDSTokenStreamPacketData();
result = tokenStream;
result.Unpack(new MemoryStream(resultBuffer));
if (tokenStream.Tokens.Any( t=> t is TDSErrorToken err))
{
this.communicatorState = TDSCommunicatorState.LoginError;
}
else
{
this.communicatorState = TDSCommunicatorState.LoggedIn;
}
break;
}

case TDSCommunicatorState.SentSqlBatch:
{
result = new TDSTokenStreamPacketData();
result.Unpack(new MemoryStream(resultBuffer));

//Restore to base state
this.communicatorState = TDSCommunicatorState.LoggedIn;
break;
}

Expand Down Expand Up @@ -268,19 +288,26 @@ public void SendTDSMessage(ITDSPacketData data)

case TDSCommunicatorState.LoggedIn:
{
throw new NotSupportedException();
}
if (!(data is TDSSqlBatchPacketData))
{
throw new InvalidDataException();
}

this.innerTdsStream.CurrentOutboundMessageType = TDSMessageType.SQLBatch;
break;
}
default:
{
throw new InvalidOperationException();
}
}

var buffer = new byte[data.Length()];
data.Pack(new MemoryStream(buffer));
var memStream = new MemoryStream(buffer);
data.Pack(memStream);

this.innerStream.Write(buffer, 0, buffer.Length);
var hex = BitConverter.ToString(buffer).Replace("-", " ");

switch (this.communicatorState)
{
Expand All @@ -295,6 +322,11 @@ public void SendTDSMessage(ITDSPacketData data)
this.communicatorState = TDSCommunicatorState.SentLogin7RecordWithCompleteAuthToken;
break;
}
case TDSCommunicatorState.LoggedIn:
{
this.communicatorState = TDSCommunicatorState.SentSqlBatch;
break;
}
}
}
}
Expand Down
12 changes: 11 additions & 1 deletion TDSClient/TDSClient/TDS/Comms/TDSCommunicatorState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ public enum TDSCommunicatorState
/// <summary>
/// LoggedIn Communicator State
/// </summary>
LoggedIn
LoggedIn,

/// <summary>
/// LoginError Communicator State
/// </summary>
LoginError,

/// <summary>
/// Sent sql batch
/// </summary>
SentSqlBatch,
}
}
Loading