Merge branch 'bugfix'
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / TdsComm.cs
1 //
2 // Mono.Data.Tds.Protocol.TdsComm.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Gonzalo Paniagua Javier (gonzalo@novell.com)
7 //
8 // Copyright (C) 2002 Tim Coleman
9 // Copyright (c) 2009 Novell, Inc.
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.IO;
35 using System.Net;
36 using System.Net.Sockets;
37 using System.Text;
38 using System.Threading;
39
40 namespace Mono.Data.Tds.Protocol {
41         internal sealed class TdsComm
42         {
43                 #region Fields
44
45                 NetworkStream stream;
46                 int packetSize;
47                 TdsPacketType packetType = TdsPacketType.None;
48                 bool connReset;
49                 Encoding encoder;
50
51                 string dataSource;
52                 int commandTimeout;
53
54                 byte[] outBuffer;
55                 int outBufferLength;
56                 int nextOutBufferIndex = 0;
57                 bool lsb;
58
59                 byte[] inBuffer;
60                 int inBufferLength;
61                 int inBufferIndex = 0;
62
63                 static int headerLength = 8;
64
65                 byte[] tmpBuf = new byte[8];
66                 byte[] resBuffer = new byte[256];
67
68                 int packetsSent;
69                 int packetsReceived = 0;
70
71                 Socket socket;
72                 TdsVersion tdsVersion;
73
74                 #endregion // Fields
75                 
76                 #region Constructors
77
78                 public TdsComm (string dataSource, int port, int packetSize, int timeout, TdsVersion tdsVersion)
79                 {
80                         this.packetSize = packetSize;
81                         this.tdsVersion = tdsVersion;
82                         this.dataSource = dataSource;
83
84                         outBuffer = new byte[packetSize];
85                         inBuffer = new byte[packetSize];
86
87                         outBufferLength = packetSize;
88                         inBufferLength = packetSize;
89
90                         lsb = true;
91                         
92                         IPEndPoint endPoint;
93                         bool have_exception = false;
94                         
95                         try {
96 #if NET_2_0
97                                 IPAddress ip;
98                                 if(IPAddress.TryParse(this.dataSource, out ip)) {
99                                         endPoint = new IPEndPoint(ip, port);
100                                 } else {
101                                         IPHostEntry hostEntry = Dns.GetHostEntry (this.dataSource);
102                                         endPoint = new IPEndPoint(hostEntry.AddressList [0], port);
103                                 }
104 #else
105                                 IPHostEntry hostEntry = Dns.Resolve (this.dataSource);
106                                 endPoint = new IPEndPoint (hostEntry.AddressList [0], port);
107 #endif
108                         } catch (SocketException e) {
109                                 throw new TdsInternalException ("Server does not exist or connection refused.", e);
110                         }
111
112                         try {
113                                 socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
114                                 IAsyncResult ares = socket.BeginConnect (endPoint, null, null);
115                                 int timeout_ms = timeout * 1000;
116                                 if (timeout > 0 && !ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne (timeout_ms, false))
117                                         throw Tds.CreateTimeoutException (dataSource, "Open()");
118                                 socket.EndConnect (ares);
119                                 try {
120                                         // MS sets these socket option
121                                         socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
122                                 } catch (SocketException) {
123                                         // Some platform may throw an exception, so
124                                         // eat all socket exception, yeaowww! 
125                                 }
126
127                                 try {
128 #if NET_2_0
129                                         socket.NoDelay = true;
130 #endif
131                                         socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout, timeout_ms);
132                                         socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout_ms);
133                                 } catch {
134                                         // Ignore exceptions here for systems that do not support these options.
135                                 }
136                                 // Let the stream own the socket and take the pleasure of closing it
137                                 stream = new NetworkStream (socket, true);
138                         } catch (SocketException e) {
139                                 have_exception = true;
140                                 throw new TdsInternalException ("Server does not exist or connection refused.", e);
141                         } catch (Exception) {
142                                 have_exception = true;
143                                 throw;
144                         } finally {
145                                 if (have_exception && socket != null) {
146                                         try {
147                                                 Socket s = socket;
148                                                 socket = null;
149                                                 s.Close ();
150                                         } catch {}
151                                 }
152                         }
153                         if (!socket.Connected)
154                                 throw new TdsInternalException ("Server does not exist or connection refused.", null);
155                         packetsSent = 1;
156                 }
157                 
158                 #endregion // Constructors
159                 
160                 #region Properties
161
162                 public int CommandTimeout {
163                         get { return commandTimeout; }
164                         set { commandTimeout = value; }
165                 }
166
167                 internal Encoding Encoder {
168                         get { return encoder; }
169                         set { encoder = value; }
170                 }
171                 
172                 public int PacketSize {
173                         get { return packetSize; }
174                         set { packetSize = value; }
175                 }
176                 
177                 public bool TdsByteOrder {
178                         get { return !lsb; }
179                         set { lsb = !value; }
180                 }
181                 #endregion // Properties
182                 
183                 #region Methods
184
185                 public byte[] Swap(byte[] toswap) {
186                         byte[] ret = new byte[toswap.Length];
187                         for(int i = 0; i < toswap.Length; i++)
188                                 ret [toswap.Length - i - 1] = toswap[i];
189
190                         return ret;
191                 }
192
193                 public void SendIfFull ()
194                 {
195                         if (nextOutBufferIndex == outBufferLength) {
196                                 SendPhysicalPacket (false);
197                                 nextOutBufferIndex = headerLength;
198                         }
199                 }
200
201                 public void SendIfFull (int reserve) 
202                 {
203                         if (nextOutBufferIndex+reserve > outBufferLength) {
204                                 SendPhysicalPacket (false);
205                                 nextOutBufferIndex = headerLength;
206                         }
207                 }
208
209                 public void Append (object o)
210                 {
211                         if (o == null || o == DBNull.Value) {
212                                 Append ((byte)0);
213                                 return ;
214                         }
215
216                         switch (Type.GetTypeCode (o.GetType ())) {
217                         case TypeCode.Byte :
218                                 Append ((byte) o);
219                                 return;
220                         case TypeCode.Boolean:
221                                 if ((bool)o == true)
222                                         Append ((byte)1);
223                                 else
224                                         Append ((byte)0);
225                                 return;
226                         case TypeCode.Object :
227                                 if (o is byte[])
228                                         Append ((byte[]) o);
229                                 return;
230                         case TypeCode.Int16 :
231                                 Append ((short) o);
232                                 return;
233                         case TypeCode.Int32 :
234                                 Append ((int) o);
235                                 return;
236                         case TypeCode.String :
237                                 Append ((string) o);
238                                 return;
239                         case TypeCode.Double :
240                                 Append ((double) o);
241                                 return;
242                         case TypeCode.Single :
243                                 Append ((float) o);
244                                 return;
245                         case TypeCode.Int64 :
246                                 Append ((long) o);
247                                 return;
248                         case TypeCode.Decimal:
249                                 Append ((decimal) o, 17);
250                                 return;
251                         case TypeCode.DateTime:
252                                 Append ((DateTime) o, 8);
253                                 return;
254                         }
255                         throw new InvalidOperationException (String.Format ("Object Type :{0} , not being appended", o.GetType ()));
256                 }
257
258                 public void Append (byte b)
259                 {
260                         SendIfFull ();
261                         Store (nextOutBufferIndex, b);
262                         nextOutBufferIndex++;
263                 }       
264
265                 public void Append (DateTime t, int bytes)
266                 {
267                         DateTime epoch = new DateTime (1900,1,1);
268                         
269                         TimeSpan span = t - epoch; //new TimeSpan (t.Ticks - epoch.Ticks);
270                         int days, hours, minutes, secs;
271                         long msecs;
272                         int val = 0;    
273
274                         days = span.Days;
275                         hours = span.Hours;
276                         minutes = span.Minutes;
277                         secs = span.Seconds;
278                         msecs = span.Milliseconds;
279                         
280                         if (epoch > t) {
281                                 // If t.Hour/Min/Sec/MSec is > 0, days points to the next day and hence, 
282                                 // we move it back by a day - otherwise, no change
283                                 days = (t.Hour > 0 || t.Minute > 0 || t.Second > 0 || t.Millisecond > 0) ? days-1: days;
284                                 hours = t.Hour;
285                                 minutes = t.Minute;
286                                 secs = t.Second;
287                                 msecs = t.Millisecond;
288                         }
289
290                         SendIfFull (bytes);
291                         if (bytes == 8) {
292                                 long ms = (hours * 3600 + minutes * 60 + secs)*1000L + (long)msecs;
293                                 val = (int) ((ms*300)/1000);
294                                 AppendInternal ((int) days);
295                                 AppendInternal ((int) val);
296                         } else if (bytes ==4) {
297                                 val = span.Hours * 60 + span.Minutes;
298                                 AppendInternal ((short) days);
299                                 AppendInternal ((short) val);
300                         } else {
301                                 throw new Exception ("Invalid No of bytes");
302                         }
303                 }
304
305                 public void Append (byte[] b)
306                 {
307                         Append (b, b.Length, (byte) 0);
308                 }
309
310                 
311                 public void Append (byte[] b, int len, byte pad)
312                 {
313                         int bufBytesToCopy = System.Math.Min (b.Length, len);
314                         int padBytesToCopy = len - bufBytesToCopy;
315                         int bufPos = 0;
316
317                         /* copy out of our input buffer in the largest chunks possible *
318                          * at a time. limited only by the buffer size for our outgoing *
319                          * packets.                                                    */
320
321                         while (bufBytesToCopy > 0)
322                         {
323                                 SendIfFull ();
324
325                                 int availBytes = outBufferLength - nextOutBufferIndex;
326                                 int bufSize = System.Math.Min (availBytes, bufBytesToCopy);
327
328                                 Buffer.BlockCopy (b, bufPos, outBuffer, nextOutBufferIndex, bufSize);
329
330                                 nextOutBufferIndex += bufSize;
331                                 bufBytesToCopy -= bufSize;
332                                 bufPos += bufSize;
333                         }
334
335                         while (padBytesToCopy > 0)
336                         {
337                                 SendIfFull ();
338
339                                 int availBytes = outBufferLength - nextOutBufferIndex;
340                                 int bufSize = System.Math.Min (availBytes, padBytesToCopy);
341
342                                 for (int i = 0; i < bufSize; i++)
343                                         outBuffer [nextOutBufferIndex++] = pad;
344
345                                 padBytesToCopy -= bufSize;
346                         }
347                 }
348
349                 private void AppendInternal (short s)
350                 {
351                         if (!lsb) {
352                                 outBuffer[nextOutBufferIndex++] = (byte) (((byte) (s >> 8)) & 0xff);
353                                 outBuffer[nextOutBufferIndex++] = (byte) ((byte) (s & 0xff));
354                         } else {
355                                 outBuffer[nextOutBufferIndex++] = (byte) ((byte) (s & 0xff));
356                                 outBuffer[nextOutBufferIndex++] = (byte) (((byte) (s >> 8)) & 0xff);
357                         }
358                 }
359
360                 public void Append (short s)
361                 {
362                         SendIfFull (sizeof (short));
363                         AppendInternal (s);
364                 }
365
366                 public void Append (ushort s)
367                 {
368                         SendIfFull (sizeof (short));
369                         AppendInternal ((short) s);
370                 }
371
372                 private void AppendInternal (int i)
373                 {
374                         if (!lsb) {
375                                 AppendInternal ((short) (((short) (i >> 16)) & 0xffff));
376                                 AppendInternal ((short) ((short) (i & 0xffff)));
377                         } else {
378                                 AppendInternal ((short) ((short) (i & 0xffff)));
379                                 AppendInternal ((short) (((short) (i >> 16)) & 0xffff));
380                         }                               
381                 }
382
383                 public void Append (int i)
384                 {
385                         SendIfFull (sizeof (int));
386                         AppendInternal (i);
387                 }
388
389                 public void Append (string s)
390                 {
391                         if (tdsVersion < TdsVersion.tds70) { 
392                                 Append (encoder.GetBytes (s));
393                         } else {
394                                 int cindex = 0, index;
395                                 int ssize = sizeof (short);
396                                 int lenToWrite = s.Length * ssize;
397                                 // if nextOutBufferLength points to the last buffer in outBuffer, 
398                                 // we would get a DivisionByZero while calculating remBufLen
399                                 if (outBufferLength - nextOutBufferIndex < ssize)
400                                         SendIfFull (ssize);
401                                 
402                                 int remBufLen = outBufferLength - nextOutBufferIndex;
403                                 int count = lenToWrite/remBufLen;
404                                 
405                                 if (lenToWrite % remBufLen > 0)
406                                         count++;
407                         
408                                 for (int i = 0; i < count; i++) {
409                                         index = System.Math.Min (remBufLen/ssize, lenToWrite/ssize);
410                                         for (int j = 0; j < index*ssize; j+=2, cindex++)
411                                                 AppendInternal ((short)s[cindex]);
412                                         
413                                         lenToWrite -= index*ssize;
414                                         // Just make sure to flush the buffer
415                                         SendIfFull ((lenToWrite+1)*ssize);
416                                 }
417                         }
418                 }       
419
420                 // Appends with padding
421                 public byte[] Append (string s, int len, byte pad)
422                 {
423                         if (s == null)
424                                 return new byte[0];
425
426                         byte[] result = encoder.GetBytes (s);
427                         Append (result, len, pad);
428                         return result;
429                 }
430
431                 public void Append (double value)
432                 {
433                         if (!lsb)
434                                 Append (Swap (BitConverter.GetBytes (value)), sizeof(double), (byte)0);
435                         else
436                                 Append (BitConverter.GetBytes (value), sizeof(double), (byte)0);
437                 }
438
439                 public void Append (float value)
440                 {
441                         if (!lsb)
442                                 Append (Swap (BitConverter.GetBytes (value)), sizeof(float), (byte)0);
443                         else
444                                 Append (BitConverter.GetBytes (value), sizeof(float), (byte)0);
445                 }
446
447                 public void Append (long l)
448                 {
449                         SendIfFull (sizeof (long));
450                         if (!lsb) {
451                                 AppendInternal ((int) (((int) (l >> 32)) & 0xffffffff));
452                                 AppendInternal ((int) ((int) (l & 0xffffffff)));
453                         } else {
454                                 AppendInternal ((int) ((int) (l & 0xffffffff)));
455                                 AppendInternal ((int) (((int) (l >> 32)) & 0xffffffff));
456                         }                               
457                 }
458
459                 public void Append (decimal d, int bytes)
460                 {
461                         int[] arr = Decimal.GetBits (d);
462                         byte sign =  (d > 0 ? (byte)1 : (byte)0);
463                         SendIfFull (bytes);
464                         Append (sign) ;
465                         AppendInternal (arr[0]);
466                         AppendInternal (arr[1]);
467                         AppendInternal (arr[2]);
468                         AppendInternal ((int)0);
469                 }
470
471                 public void Close ()
472                 {
473                         if (stream == null)
474                                 return;
475
476                         connReset = false;
477                         socket = null;
478                         try {
479                                 stream.Close ();
480                         } catch {
481                         }
482                         stream = null;
483                 }
484
485                 public bool IsConnected () 
486                 {
487                         return socket != null && socket.Connected && !(socket.Poll (0, SelectMode.SelectRead) && socket.Available == 0);
488                 }
489                 
490                 public byte GetByte ()
491                 {
492                         byte result;
493
494                         if (inBufferIndex >= inBufferLength) {
495                                 // out of data, read another physical packet.
496                                 GetPhysicalPacket ();
497                         }
498                         result = inBuffer[inBufferIndex++];
499                         return result;
500                 }
501
502                 public byte[] GetBytes (int len, bool exclusiveBuffer)
503                 {
504                         byte[] result = null;
505                         int i;
506
507                         // Do not keep an internal result buffer larger than 16k.
508                         // This would unnecessarily use up memory.
509                         if (exclusiveBuffer || len > 16384)
510                                 result = new byte[len];
511                         else
512                         {
513                                 if (resBuffer.Length < len)
514                                         resBuffer = new byte[len];
515                                 result = resBuffer;
516                         }
517
518                         for (i = 0; i<len; )
519                         {
520                                 if (inBufferIndex >= inBufferLength)
521                                         GetPhysicalPacket ();
522
523                                 int avail = inBufferLength - inBufferIndex;
524                                 avail = avail>len-i ? len-i : avail;
525
526                                 Buffer.BlockCopy (inBuffer, inBufferIndex, result, i, avail);
527                                 i += avail;
528                                 inBufferIndex += avail;
529                         }
530
531                         return result;
532                 }
533
534                 public string GetString (int len, Encoding enc)
535                 {
536                         if (tdsVersion >= TdsVersion.tds70) 
537                                 return GetString (len, true, null);
538                         else
539                                 return GetString (len, false, null);
540                 }
541                 
542                 public string GetString (int len)
543                 {
544                         if (tdsVersion >= TdsVersion.tds70) 
545                                 return GetString (len, true);
546                         else
547                                 return GetString (len, false);
548                 }
549
550                 public string GetString (int len, bool wide, Encoding enc)
551                 {
552                         if (wide) {
553                                 char[] chars = new char[len];
554                                 for (int i = 0; i < len; ++i) {
555                                         int lo = ((byte) GetByte ()) & 0xFF;
556                                         int hi = ((byte) GetByte ()) & 0xFF;
557                                         chars[i] = (char) (lo | ( hi << 8));
558                                 }
559                                 return new String (chars);
560                         }
561                         else {
562                                 byte[] result = new byte[len];
563                                 Array.Copy (GetBytes (len, false), result, len);
564                                 // Use the passed encoder, if available
565                                 if (enc != null)
566                                         return (enc.GetString (result));
567                                 else
568                                         return (encoder.GetString (result));
569                         }
570                 }
571                 
572                 public string GetString (int len, bool wide)
573                 {
574                         return GetString (len, wide, null);
575                 }
576
577                 public int GetNetShort ()
578                 {
579                         byte[] tmp = new byte[2];
580                         tmp[0] = GetByte ();
581                         tmp[1] = GetByte ();
582                         return Ntohs (tmp, 0);
583                 }
584
585                 public short GetTdsShort ()
586                 {
587                         byte[] input = new byte[2];
588
589                         for (int i = 0; i < 2; i += 1)
590                                 input[i] = GetByte ();
591                         if(!BitConverter.IsLittleEndian)
592                                 return (BitConverter.ToInt16 (Swap (input), 0));
593                         else
594                                 return (BitConverter.ToInt16 (input, 0));
595                 }
596
597
598                 public int GetTdsInt ()
599                 {
600                         byte[] input = new byte[4];
601                         for (int i = 0; i < 4; i += 1) {
602                                 input[i] = GetByte ();
603                         }
604                         if(!BitConverter.IsLittleEndian)
605                                 return (BitConverter.ToInt32 (Swap (input), 0));
606                         else
607                                 return (BitConverter.ToInt32 (input, 0));
608                 }
609
610                 public long GetTdsInt64 ()
611                 {
612                         byte[] input = new byte[8];
613                         for (int i = 0; i < 8; i += 1)
614                                 input[i] = GetByte ();
615                         if(!BitConverter.IsLittleEndian)
616                                 return (BitConverter.ToInt64 (Swap (input), 0));
617                         else
618                                 return (BitConverter.ToInt64 (input, 0));
619                 }
620
621                 private void GetPhysicalPacket ()
622                 {
623                         int dataLength = GetPhysicalPacketHeader ();
624                         GetPhysicalPacketData (dataLength);
625                 }
626
627                 int Read (byte [] buffer, int offset, int count)
628                 {
629                         try {
630                                 return stream.Read (buffer, offset, count);
631                         } catch {
632                                 socket = null;
633                                 stream.Close ();
634                                 throw;
635                         }
636                 }
637
638                 private int GetPhysicalPacketHeader ()
639                 {
640                         int nread = 0;
641
642                         int n;
643                         // read the header
644                         while (nread < 8) {
645                                 n = Read (tmpBuf, nread, 8 - nread);
646                                 if (n <= 0) {
647                                         socket = null;
648                                         stream.Close ();
649                                         throw new IOException (n == 0 ? "Connection lost" : "Connection error");
650                                 }
651                                 nread += n;
652                         }
653
654                         TdsPacketType packetType = (TdsPacketType) tmpBuf[0];
655                         if (packetType != TdsPacketType.Logon && packetType != TdsPacketType.Query && packetType != TdsPacketType.Reply) 
656                         {
657                                 throw new Exception (String.Format ("Unknown packet type {0}", tmpBuf[0]));
658                         }
659
660                         // figure out how many bytes are remaining in this packet.
661                         int len = Ntohs (tmpBuf, 2) - 8;
662                         if (len >= inBuffer.Length) 
663                                 inBuffer = new byte[len];
664
665                         if (len < 0) {
666                                 throw new Exception (String.Format ("Confused by a length of {0}", len));
667                         }
668                         
669                         return len;
670
671                 }
672                 
673                 private void GetPhysicalPacketData (int length)
674                 {
675                         // now get the data
676                         int nread = 0;
677                         int n;
678
679                         while (nread < length) {
680                                 n = Read (inBuffer, nread, length - nread);
681                                 if (n <= 0) {
682                                         socket = null;
683                                         stream.Close ();
684                                         throw new IOException (n == 0 ? "Connection lost" : "Connection error");
685                                 }
686                                 nread += n;
687                         }
688
689                         packetsReceived++;
690
691                         // adjust the bookkeeping info about the incoming buffer
692                         inBufferLength = length;
693                         inBufferIndex = 0;
694                 }
695                 
696
697                 private static int Ntohs (byte[] buf, int offset)
698                 {
699                         int lo = ((int) buf[offset + 1] & 0xff);
700                         int hi = (((int) buf[offset] & 0xff ) << 8);
701
702                         return hi | lo;
703                         // return an int since we really want an _unsigned_
704                 }               
705
706                 public byte Peek ()
707                 {
708                         // If out of data, read another physical packet.
709                         if (inBufferIndex >= inBufferLength)
710                                 GetPhysicalPacket ();
711
712                         return inBuffer[inBufferIndex];
713                 }
714
715                 public bool Poll (int seconds, SelectMode selectMode)
716                 {
717                         return Poll (socket, seconds, selectMode);
718                 }
719
720                 private bool Poll (Socket s, int seconds, SelectMode selectMode)
721                 {
722                         long uSeconds = seconds * 1000000;
723                         bool bState = false;
724
725                         while (uSeconds > (long) Int32.MaxValue) {
726                                 bState = s.Poll (Int32.MaxValue, selectMode);
727                                 if (bState) 
728                                         return true;
729                                 uSeconds -= Int32.MaxValue;
730                         }
731                         return s.Poll ((int) uSeconds, selectMode);
732                 }
733
734                 internal void ResizeOutBuf (int newSize)
735                 {
736                         if (newSize != outBufferLength) {
737                                 byte[] newBuf = new byte [newSize];
738                                 Buffer.BlockCopy (outBuffer, 0, newBuf, 0, newSize);
739                                 outBufferLength = newSize;
740                                 outBuffer = newBuf;
741                         }
742                 }
743
744                 public bool ResetConnection {
745                         get { return connReset; }
746                         set { connReset = value; }
747                 }
748
749                 public void SendPacket ()
750                 {
751                         // Reset connection flag is only valid for SQLBatch/RPC/DTC messages
752                         if (packetType != TdsPacketType.Query && packetType != TdsPacketType.RPC)
753                                 connReset = false;
754                         
755                         SendPhysicalPacket (true);
756                         nextOutBufferIndex = 0;
757                         packetType = TdsPacketType.None;
758                         // Reset connection-reset flag to false - as any exception would anyway close 
759                         // the whole connection
760                         connReset = false;
761                         packetsSent = 1;
762                 }
763                 
764                 private void SendPhysicalPacket (bool isLastSegment)
765                 {
766                         if (nextOutBufferIndex > headerLength || packetType == TdsPacketType.Cancel) {
767                                 byte status =  (byte) ((isLastSegment ? 0x01 : 0x00) | (connReset ? 0x08 : 0x00)); 
768                                 // packet type
769                                 Store (0, (byte) packetType);
770                                 Store (1, status);
771                                 Store (2, (short) nextOutBufferIndex );
772                                 Store (4, (byte) 0);
773                                 Store (5, (byte) 0);
774                                 if (tdsVersion >= TdsVersion.tds70)
775                                         Store (6, (byte) packetsSent);
776                                 else    
777                                         Store (6, (byte) 0);
778                                 Store (7, (byte) 0);
779
780                                 stream.Write (outBuffer, 0, nextOutBufferIndex);
781                                 stream.Flush ();
782                                 packetsSent++;
783                         }
784                 }
785                 
786                 public void Skip (long i)
787                 {
788                         for ( ; i > 0; i--)
789                                 GetByte ();
790                 }
791
792                 public void StartPacket (TdsPacketType type)
793                 {
794                         if (type != TdsPacketType.Cancel && inBufferIndex != inBufferLength)
795                                 inBufferIndex = inBufferLength;
796
797                         packetType = type;
798                         nextOutBufferIndex = headerLength;
799                 }
800
801                 private void Store (int index, byte value)
802                 {
803                         outBuffer[index] = value;
804                 }               
805
806                 private void Store (int index, short value)
807                 {
808                         outBuffer[index] = (byte) (((byte) (value >> 8)) & 0xff);
809                         outBuffer[index + 1] = (byte) (((byte) (value >> 0)) & 0xff);
810                 }
811
812                 #endregion // Methods
813 #if NET_2_0
814                 #region Async Methods
815
816                 public IAsyncResult BeginReadPacket (AsyncCallback callback, object stateObject)
817                 {
818                         TdsAsyncResult ar = new TdsAsyncResult (callback, stateObject);
819
820                         stream.BeginRead (tmpBuf, 0, 8, new AsyncCallback(OnReadPacketCallback), ar);
821                         return ar;
822                 }
823                 
824                 /// <returns>Packet size in bytes</returns>
825                 public int EndReadPacket (IAsyncResult ar)
826                 {
827                         if (!ar.IsCompleted)
828                                 ar.AsyncWaitHandle.WaitOne ();
829                         return (int) ((TdsAsyncResult) ar).ReturnValue;
830                 }
831                 
832
833                 public void OnReadPacketCallback (IAsyncResult socketAsyncResult)
834                 {
835                         TdsAsyncResult ar = (TdsAsyncResult) socketAsyncResult.AsyncState;
836                         int nread = stream.EndRead (socketAsyncResult);
837                         int n;
838                         
839                         while (nread < 8) {
840                                 n = Read (tmpBuf, nread, 8 - nread);
841                                 if (n <= 0) {
842                                         socket = null;
843                                         stream.Close ();
844                                         throw new IOException (n == 0 ? "Connection lost" : "Connection error");
845                                 }
846                                 nread += n;
847                         }
848
849                         TdsPacketType packetType = (TdsPacketType) tmpBuf[0];
850                         if (packetType != TdsPacketType.Logon && packetType != TdsPacketType.Query && packetType != TdsPacketType.Reply) 
851                         {
852                                 throw new Exception (String.Format ("Unknown packet type {0}", tmpBuf[0]));
853                         }
854
855                         // figure out how many bytes are remaining in this packet.
856                         int len = Ntohs (tmpBuf, 2) - 8;
857
858                         if (len >= inBuffer.Length) 
859                                 inBuffer = new byte[len];
860
861                         if (len < 0) {
862                                 throw new Exception (String.Format ("Confused by a length of {0}", len));
863                         }
864
865                         GetPhysicalPacketData (len);
866                         int value = len + 8;
867                         ar.ReturnValue = ((object)value); // packet size
868                         ar.MarkComplete ();
869                 }
870                 
871                 #endregion // Async Methods
872 #endif // NET_2_0
873
874         }
875
876 }