-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMessages.cs
134 lines (112 loc) · 5.83 KB
/
Messages.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
Copyright 2014 Matthew Wilkinson
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System.IO;
using System.Text;
namespace System.Data.Sql
{
internal static class Messages
{
/// <summary>
/// The CLNT_BCAST_EX packet is a broadcast or multicast request that is generated by clients that are trying to identify the list of database instances on the network and their network protocol connection information.
/// </summary>
/// <seealso href="http://msdn.microsoft.com/en-us/library/cc219743.aspx">2.2.1 CLNT_BCAST_EX</seealso>
/// <returns>Array of bytes containing the CLNT_BCAST_EX message</returns>
/// <remarks>Always returns fresh array to prevent consumer from modifying array if we were to optimise as a single array instance.</remarks>
public static byte[] ClientBroadcastEx() => new byte[] { 0x02 };
/// <summary>
/// The CLNT_UCAST_EX packet is a unicast request that is generated by clients that are trying to identify the list of database instances and their network protocol connection information installed on a single machine. The client generates a UDP packet with a single byte.
/// </summary>
/// <seealso href="http://msdn.microsoft.com/en-us/library/cc219745.aspx">2.2.2 CLNT_UCAST_EX</seealso>
/// <returns>Array of bytes containing the CLNT_UCAST_EX message</returns>
/// <remarks>Always returns fresh array to prevent consumer from modifying array if we were to optimise as a single array instance.</remarks>
public static byte[] ClientUnicastEx() => new byte[] { 0x03 };
/// <summary>
/// The CLNT_UCAST_INST packet is a request for information related to a specific instance.
/// </summary>
/// <param name="instanceName">Name of the instance to request information about.</param>
/// <returns>Array of bytes containing the CLNT_UCAST_INST message</returns>
public static byte[] ClientUnicastInstance(string instanceName)
{
var instanceNameBytes = GetInstanceNameBytes(instanceName);
var returnBytes = new byte[2 + instanceNameBytes.Length];
returnBytes[0] = 0x04;
instanceNameBytes.CopyTo(returnBytes, 1);
returnBytes[returnBytes.Length - 1] = 0x00;
return returnBytes;
}
/// <summary>
/// The CLNT_UCAST_DAC packet request is used to determine the TCP port on which the SQL Server dedicated administrator connection (DAC) endpoint is listening.
/// </summary>
/// <param name="instanceName">Name of the instance to request information about.</param>
/// <returns>Array of bytes containing the CLNT_UCAST_DAC message</returns>
public static byte[] ClientUnicastDac(string instanceName)
{
var instanceNameBytes = GetInstanceNameBytes(instanceName);
var returnBytes = new byte[3 + instanceNameBytes.Length];
returnBytes[0] = 0x0F;
returnBytes[1] = 0x01;
instanceNameBytes.CopyTo(returnBytes, 2);
returnBytes[returnBytes.Length - 1] = 0x00;
return returnBytes;
}
/// <summary>
/// The server responds to all client requests with an SVR_RESP.
/// </summary>
/// <param name="response">The bytes that were received in response.</param>
/// <returns>The string returned from the server.</returns>
public static string ServerResponse(byte[] response)
{
if (response[0] != 0x05)
{
throw new InvalidDataException("Invalid SVR_RESP message");
}
int size = (response[2] << 8) + response[1];
return Encoding.Default.GetString(response, 3, size);
}
/// <summary>
/// The format of the SVR_RESP is different for a CLNT_UCAST_DAC request only.
/// </summary>
/// <param name="response">The bytes that were received in response.</param>
/// <returns>The value of the TCP port number that is used for DAC.</returns>
public static int ServerResponseDac(byte[] response)
{
if (response.Length != 6
|| response[0] != 0x05 // SVR_RESP
|| response[1] != 0x06 || response[2] != 0x00 // RESP_SIZE 0x06 over 2 bytes (little-endian)
|| response[3] != 0x01 // PROTOCOL_VERSION
)
{
throw new InvalidDataException("Invalid SVR_RESP (DAC) message");
}
return (response[5] << 8) + response[4];
}
private static byte[] GetInstanceNameBytes(string instanceName)
{
if (string.IsNullOrWhiteSpace(instanceName))
{
throw new ArgumentException("Instance name cannot be empty", "instanceName");
}
if (instanceName.Length > 32)
{
throw new ArgumentOutOfRangeException("instanceName", "Instance name cannot be longer than 32 characters");
}
var byteCount = Encoding.Default.GetByteCount(instanceName);
if (byteCount > 32)
{
throw new ArgumentOutOfRangeException("instanceName",
"Instance name encodes to greater than 32 bytes");
}
return Encoding.Default.GetBytes(instanceName);
}
}
}