2 // Mono.Data.TdsClient.Internal.TdsComm.cs
5 // Tim Coleman (tim@timcoleman.com)
7 // Copyright (C) 2002 Tim Coleman
11 using System.Net.Sockets;
13 using System.Threading;
15 namespace Mono.Data.TdsClient.Internal {
16 internal sealed class TdsComm
22 TdsPacketType packetType = TdsPacketType.None;
27 int nextOutBufferIndex = 0;
31 int inBufferIndex = 0;
33 static int headerLength = 8;
35 byte[] tmpBuf = new byte[8];
36 byte[] resBuffer = new byte[256];
39 int packetsReceived = 0;
41 TdsVersion tdsVersion;
47 public TdsComm (Socket socket, int packetSize, TdsVersion tdsVersion)
49 this.packetSize = packetSize;
50 this.tdsVersion = tdsVersion;
52 outBuffer = new byte[packetSize];
53 inBuffer = new byte[packetSize];
55 outBufferLength = packetSize;
56 inBufferLength = packetSize;
57 stream = new NetworkStream (socket);
60 #endregion // Constructors
64 internal Encoding Encoder {
65 set { encoder = value; }
68 public int PacketSize {
69 get { return packetSize; }
70 set { packetSize = value; }
73 #endregion // Properties
77 internal void ResizeOutBuf (int newSize)
79 if (newSize > outBufferLength) {
80 byte[] newBuf = new byte[newSize];
81 Array.Copy (outBuffer, 0, newBuf, 0, outBufferLength);
82 outBufferLength = newSize;
87 public void StartPacket (TdsPacketType type)
89 if (type != TdsPacketType.Cancel && inBufferIndex != inBufferLength)
91 // SAfe It's ok to throw this exception so that we will know there
92 // is a design flaw somewhere, but we should empty the buffer
93 // however. Otherwise the connection will never close (e.g. if
94 // SHOWPLAN_ALL is ON, a resultset will be returned by commit
95 // or rollback and we will never get rid of it). It's true
96 // that we should find a way to actually process these packets
97 // but for now, just dump them (we have thrown an exception).
98 inBufferIndex = inBufferLength;
102 nextOutBufferIndex = headerLength;
105 public bool SomeThreadIsBuildingPacket ()
107 return packetType != TdsPacketType.None;
110 public void Append (byte b)
112 if (nextOutBufferIndex == outBufferLength) {
113 SendPhysicalPacket (false);
114 nextOutBufferIndex = headerLength;
116 StoreByte (nextOutBufferIndex, b);
117 nextOutBufferIndex++;
120 public void Append (byte[] b)
122 Append (b, b.Length, (byte) 0);
125 public void Append (byte[] b, int len, byte pad)
128 for ( ; i < b.Length && i < len; i++)
131 for ( ; i < len; i++)
135 public void Append (short s)
137 if (tdsVersion < TdsVersion.tds70) {
138 Append ((byte) (((byte) (s >> 8)) & 0xff));
139 Append ((byte) (((byte) (s >> 0)) & 0xff));
142 Append (BitConverter.GetBytes (s));
145 public void Append (int i)
147 if (tdsVersion < TdsVersion.tds70) {
148 Append ((byte) (((byte) (i >> 24)) & 0xff));
149 Append ((byte) (((byte) (i >> 16)) & 0xff));
150 Append ((byte) (((byte) (i >> 8)) & 0xff));
151 Append ((byte) (((byte) (i >> 0)) & 0xff));
154 Append (BitConverter.GetBytes (i));
157 public void Append (string s)
159 if (tdsVersion < TdsVersion.tds70)
160 Append (encoder.GetBytes (s));
162 foreach (char c in s)
163 Append (BitConverter.GetBytes (c));
166 // Appends with padding
167 public byte[] Append (string s, int len, byte pad)
172 byte[] result = encoder.GetBytes (s);
173 Append (result, len, pad);
177 public void Append (double value)
179 Append (BitConverter.DoubleToInt64Bits (value));
182 public void Append (long l)
184 if (tdsVersion < TdsVersion.tds70) {
185 Append ((byte) (((byte) (l >> 56)) & 0xff));
186 Append ((byte) (((byte) (l >> 48)) & 0xff));
187 Append ((byte) (((byte) (l >> 40)) & 0xff));
188 Append ((byte) (((byte) (l >> 32)) & 0xff));
189 Append ((byte) (((byte) (l >> 24)) & 0xff));
190 Append ((byte) (((byte) (l >> 16)) & 0xff));
191 Append ((byte) (((byte) (l >> 8)) & 0xff));
192 Append ((byte) (((byte) (l >> 0)) & 0xff));
195 Append (BitConverter.GetBytes (l));
199 public void SendPacket ()
201 SendPhysicalPacket (true);
202 nextOutBufferIndex = 0;
203 packetType = TdsPacketType.None;
206 private void StoreByte (int index, byte value)
208 outBuffer[index] = value;
211 private void StoreShort (int index, short s)
213 outBuffer[index] = (byte) (((byte) (s >> 8)) & 0xff);
214 outBuffer[index + 1] = (byte) (((byte) (s >> 0)) & 0xff);
217 private void SendPhysicalPacket (bool isLastSegment)
219 if (nextOutBufferIndex > headerLength || packetType == TdsPacketType.Cancel) {
221 StoreByte (0, (byte) packetType);
222 StoreByte (1, (byte) (isLastSegment ? 1 : 0));
223 StoreShort (2, (short) nextOutBufferIndex );
224 StoreByte (4, (byte) 0);
225 StoreByte (5, (byte) 0);
226 StoreByte (6, (byte) (tdsVersion == TdsVersion.tds70 ? 0x1 : 0x0));
227 StoreByte (7, (byte) 0);
229 stream.Write (outBuffer, 0, nextOutBufferIndex);
237 // If out of data, read another physical packet.
238 if (inBufferIndex >= inBufferLength)
239 GetPhysicalPacket ();
241 return inBuffer[inBufferIndex];
245 public byte GetByte ()
249 if (inBufferIndex >= inBufferLength) {
250 // out of data, read another physical packet.
251 GetPhysicalPacket ();
254 result = inBuffer[inBufferIndex++];
258 public byte[] GetBytes (int len, bool exclusiveBuffer)
260 byte[] result = null;
263 // Do not keep an internal result buffer larger than 16k.
264 // This would unnecessarily use up memory.
265 if (exclusiveBuffer || len > 16384)
266 result = new byte[len];
269 if (resBuffer.Length < len)
270 resBuffer = new byte[len];
276 if (inBufferIndex >= inBufferLength)
277 GetPhysicalPacket ();
279 int avail = inBufferLength - inBufferIndex;
280 avail = avail>len-i ? len-i : avail;
282 System.Array.Copy (inBuffer, inBufferIndex, result, i, avail);
284 inBufferIndex += avail;
290 public string GetString (int len)
292 if (tdsVersion == TdsVersion.tds70) {
293 char[] chars = new char[len];
294 for (int i = 0; i < len; ++i) {
295 int lo = ((byte) GetByte ()) & 0xFF;
296 int hi = ((byte) GetByte ()) & 0xFF;
297 chars[i] = (char) (lo | ( hi << 8));
299 return new String (chars);
302 byte[] result = new byte[len + 1];
303 Array.Copy (GetBytes (len, false), result, len);
304 result[len] = (byte) 0;
305 return (encoder.GetString (result));
309 public void Skip (int i)
317 public int GetNetShort ()
319 byte[] tmp = new byte[2];
322 return Ntohs (tmp, 0);
325 public short GetTdsShort ()
327 byte[] input = new byte[2];
329 for (int i = 0; i < 2; i += 1)
330 input[i] = GetByte ();
332 return (BitConverter.ToInt16 (input, 0));
336 public int GetTdsInt ()
338 byte[] input = new byte[4];
339 for (int i = 0; i < 4; i += 1)
340 input[i] = GetByte ();
341 return (BitConverter.ToInt32 (input, 0));
344 public long GetTdsInt64 ()
346 byte[] input = new byte[8];
347 for (int i = 0; i < 8; i += 1)
348 input[i] = GetByte ();
349 return (BitConverter.ToInt64 (input, 0));
352 private void GetPhysicalPacket ()
358 nread += stream.Read (tmpBuf, nread, 8 - nread);
360 TdsPacketType packetType = (TdsPacketType) tmpBuf[0];
361 if (packetType != TdsPacketType.Logon && packetType != TdsPacketType.Query && packetType != TdsPacketType.Reply) {
362 throw new TdsException (String.Format ("Unknown packet type {0}", tmpBuf[0]));
365 // figure out how many bytes are remaining in this packet.
366 int len = Ntohs (tmpBuf, 2) - 8;
368 if (len >= inBuffer.Length)
369 inBuffer = new byte[len];
372 throw new TdsException (String.Format ("Confused by a length of {0}", len));
377 while (nread < len) {
378 nread += stream.Read (inBuffer, nread, len - nread);
383 // adjust the bookkeeping info about the incoming buffer
384 inBufferLength = len;
388 private static int Ntohs (byte[] buf, int offset)
390 int lo = ((int) buf[offset + 1] & 0xff);
391 int hi = (((int) buf[offset] & 0xff ) << 8);
394 // return an int since we really want an _unsigned_
396 #endregion // Methods