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 (Encoding encoder, Socket socket, int packetSize, TdsVersion tdsVersion)
49 this.encoder = encoder;
50 this.packetSize = packetSize;
51 this.tdsVersion = tdsVersion;
53 outBuffer = new byte[packetSize];
54 inBuffer = new byte[packetSize];
56 outBufferLength = packetSize;
57 inBufferLength = packetSize;
58 stream = new NetworkStream (socket);
61 #endregion // Constructors
65 public int PacketSize {
66 get { return packetSize; }
67 set { packetSize = value; }
70 #endregion // Properties
74 internal void ResizeOutBuf (int newSize)
76 if (newSize > outBufferLength) {
77 byte[] newBuf = new byte[newSize];
78 Array.Copy (outBuffer, 0, newBuf, 0, outBufferLength);
79 outBufferLength = newSize;
84 public void StartPacket (TdsPacketType type)
86 if (type != TdsPacketType.Cancel && inBufferIndex != inBufferLength)
88 // SAfe It's ok to throw this exception so that we will know there
89 // is a design flaw somewhere, but we should empty the buffer
90 // however. Otherwise the connection will never close (e.g. if
91 // SHOWPLAN_ALL is ON, a resultset will be returned by commit
92 // or rollback and we will never get rid of it). It's true
93 // that we should find a way to actually process these packets
94 // but for now, just dump them (we have thrown an exception).
95 inBufferIndex = inBufferLength;
99 nextOutBufferIndex = headerLength;
102 public bool SomeThreadIsBuildingPacket ()
104 return packetType != TdsPacketType.None;
107 public void Append (byte b)
109 if (nextOutBufferIndex == outBufferLength) {
110 SendPhysicalPacket (false);
111 nextOutBufferIndex = headerLength;
113 StoreByte (nextOutBufferIndex, b);
114 nextOutBufferIndex++;
117 public void Append (byte[] b)
119 Append (b, b.Length, (byte) 0);
122 public void Append (byte[] b, int len, byte pad)
125 for ( ; i < b.Length && i < len; i++)
128 for ( ; i < len; i++)
132 public void Append (short s)
134 if (tdsVersion < TdsVersion.tds70) {
135 Append ((byte) (((byte) (s >> 8)) & 0xff));
136 Append ((byte) (((byte) (s >> 0)) & 0xff));
139 Append (BitConverter.GetBytes (s));
142 public void Append (int i)
144 if (tdsVersion < TdsVersion.tds70) {
145 Append ((byte) (((byte) (i >> 24)) & 0xff));
146 Append ((byte) (((byte) (i >> 16)) & 0xff));
147 Append ((byte) (((byte) (i >> 8)) & 0xff));
148 Append ((byte) (((byte) (i >> 0)) & 0xff));
151 Append (BitConverter.GetBytes (i));
154 public void Append (string s)
156 if (tdsVersion < TdsVersion.tds70)
157 Append (encoder.GetBytes (s));
159 foreach (char c in s)
160 Append (BitConverter.GetBytes (c));
163 // Appends with padding
164 public byte[] Append (string s, int len, byte pad)
166 byte[] result = encoder.GetBytes (s);
167 Append (result, len, pad);
171 public void Append (double value)
173 Append (BitConverter.DoubleToInt64Bits (value));
176 public void Append (long l)
178 if (tdsVersion < TdsVersion.tds70) {
179 Append ((byte) (((byte) (l >> 56)) & 0xff));
180 Append ((byte) (((byte) (l >> 48)) & 0xff));
181 Append ((byte) (((byte) (l >> 40)) & 0xff));
182 Append ((byte) (((byte) (l >> 32)) & 0xff));
183 Append ((byte) (((byte) (l >> 24)) & 0xff));
184 Append ((byte) (((byte) (l >> 16)) & 0xff));
185 Append ((byte) (((byte) (l >> 8)) & 0xff));
186 Append ((byte) (((byte) (l >> 0)) & 0xff));
189 Append (BitConverter.GetBytes (l));
193 public void SendPacket ()
195 SendPhysicalPacket (true);
196 nextOutBufferIndex = 0;
197 packetType = TdsPacketType.None;
200 private void StoreByte (int index, byte value)
202 outBuffer[index] = value;
205 private void StoreShort (int index, short s)
207 outBuffer[index] = (byte) (((byte) (s >> 8)) & 0xff);
208 outBuffer[index + 1] = (byte) (((byte) (s >> 0)) & 0xff);
211 private void SendPhysicalPacket (bool isLastSegment)
213 if (nextOutBufferIndex > headerLength || packetType == TdsPacketType.Cancel) {
215 StoreByte (0, (byte) packetType);
216 StoreByte (1, (byte) (isLastSegment ? 1 : 0));
217 StoreShort (2, (short) nextOutBufferIndex );
218 StoreByte (4, (byte) 0);
219 StoreByte (5, (byte) 0);
220 StoreByte (6, (byte) (tdsVersion == TdsVersion.tds70 ? 0x1 : 0x0));
221 StoreByte (7, (byte) 0);
223 stream.Write (outBuffer, 0, nextOutBufferIndex);
231 // If out of data, read another physical packet.
232 if (inBufferIndex >= inBufferLength)
233 GetPhysicalPacket ();
235 return inBuffer[inBufferIndex];
239 public byte GetByte ()
243 if (inBufferIndex >= inBufferLength) {
244 // out of data, read another physical packet.
245 GetPhysicalPacket ();
248 result = inBuffer[inBufferIndex++];
252 public byte[] GetBytes (int len, bool exclusiveBuffer)
254 byte[] result = null;
257 // Do not keep an internal result buffer larger than 16k.
258 // This would unnecessarily use up memory.
259 if (exclusiveBuffer || len > 16384)
260 result = new byte[len];
263 if (resBuffer.Length < len)
264 resBuffer = new byte[len];
270 if (inBufferIndex >= inBufferLength)
271 GetPhysicalPacket ();
273 int avail = inBufferLength - inBufferIndex;
274 avail = avail>len-i ? len-i : avail;
276 System.Array.Copy (inBuffer, inBufferIndex, result, i, avail);
278 inBufferIndex += avail;
284 public string GetString (int len)
286 if (tdsVersion == TdsVersion.tds70) {
287 char[] chars = new char[len];
288 for (int i = 0; i < len; ++i) {
289 int lo = ((byte) GetByte ()) & 0xFF;
290 int hi = ((byte) GetByte ()) & 0xFF;
291 chars[i] = (char) (lo | ( hi << 8));
293 return new String (chars);
296 byte[] result = new byte[len + 1];
297 Array.Copy (GetBytes (len, false), result, len);
298 result[len] = (byte) 0;
299 return (encoder.GetString (result));
303 public void Skip (int i)
311 public int GetNetShort ()
313 byte[] tmp = new byte[2];
316 return Ntohs (tmp, 0);
319 public short GetTdsShort ()
321 byte[] input = new byte[2];
323 for (int i = 0; i < 2; i += 1)
324 input[i] = GetByte ();
326 return (BitConverter.ToInt16 (input, 0));
330 public int GetTdsInt ()
332 byte[] input = new byte[4];
333 for (int i = 0; i < 4; i += 1)
334 input[i] = GetByte ();
335 return (BitConverter.ToInt32 (input, 0));
338 public long GetTdsInt64 ()
340 byte[] input = new byte[8];
341 for (int i = 0; i < 8; i += 1)
342 input[i] = GetByte ();
343 return (BitConverter.ToInt64 (input, 0));
346 private void GetPhysicalPacket ()
352 nread += stream.Read (tmpBuf, nread, 8 - nread);
354 TdsPacketType packetType = (TdsPacketType) tmpBuf[0];
355 if (packetType != TdsPacketType.Logon && packetType != TdsPacketType.Query && packetType != TdsPacketType.Reply) {
356 throw new TdsException (String.Format ("Unknown packet type {0}", tmpBuf[0]));
359 // figure out how many bytes are remaining in this packet.
360 int len = Ntohs (tmpBuf, 2) - 8;
362 if (len >= inBuffer.Length)
363 inBuffer = new byte[len];
366 throw new TdsException (String.Format ("Confused by a length of {0}", len));
371 while (nread < len) {
372 nread += stream.Read (inBuffer, nread, len - nread);
377 // adjust the bookkeeping info about the incoming buffer
378 inBufferLength = len;
382 private static int Ntohs (byte[] buf, int offset)
384 int lo = ((int) buf[offset + 1] & 0xff);
385 int hi = (((int) buf[offset] & 0xff ) << 8);
388 // return an int since we really want an _unsigned_
390 #endregion // Methods