2010-07-07 Veerapuram Varadhan <vvaradhan@novell.com>
[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 is > 0, days points to the next day and hence, 
282                                 // we move it back by a day - otherwise, no change
283                                 if (t.Hour > 0) {
284                                         days--;
285                                         hours = t.Hour;
286                                 } else {
287                                         hours = 12;
288                                 }
289                                 
290                                 minutes = t.Minute;
291                                 secs = t.Second;
292                                 msecs = t.Millisecond;
293                         }
294
295                         SendIfFull (bytes);
296                         if (bytes == 8) {
297                                 long ms = (hours * 3600 + minutes * 60 + secs)*1000L + (long)msecs;
298                                 val = (int) ((ms*300)/1000);
299                                 AppendInternal ((int) days);
300                                 AppendInternal ((int) val);
301                         } else if (bytes ==4) {
302                                 val = span.Hours * 60 + span.Minutes;
303                                 AppendInternal ((short) days);
304                                 AppendInternal ((short) val);
305                         } else {
306                                 throw new Exception ("Invalid No of bytes");
307                         }
308                 }
309
310                 public void Append (byte[] b)
311                 {
312                         Append (b, b.Length, (byte) 0);
313                 }
314
315                 
316                 public void Append (byte[] b, int len, byte pad)
317                 {
318                         int bufBytesToCopy = System.Math.Min (b.Length, len);
319                         int padBytesToCopy = len - bufBytesToCopy;
320                         int bufPos = 0;
321
322                         /* copy out of our input buffer in the largest chunks possible *
323                          * at a time. limited only by the buffer size for our outgoing *
324                          * packets.                                                    */
325
326                         while (bufBytesToCopy > 0)
327                         {
328                                 SendIfFull ();
329
330                                 int availBytes = outBufferLength - nextOutBufferIndex;
331                                 int bufSize = System.Math.Min (availBytes, bufBytesToCopy);
332
333                                 Buffer.BlockCopy (b, bufPos, outBuffer, nextOutBufferIndex, bufSize);
334
335                                 nextOutBufferIndex += bufSize;
336                                 bufBytesToCopy -= bufSize;
337                                 bufPos += bufSize;
338                         }
339
340                         while (padBytesToCopy > 0)
341                         {
342                                 SendIfFull ();
343
344                                 int availBytes = outBufferLength - nextOutBufferIndex;
345                                 int bufSize = System.Math.Min (availBytes, padBytesToCopy);
346
347                                 for (int i = 0; i < bufSize; i++)
348                                         outBuffer [nextOutBufferIndex++] = pad;
349
350                                 padBytesToCopy -= bufSize;
351                         }
352                 }
353
354                 private void AppendInternal (short s)
355                 {
356                         if (!lsb) {
357                                 outBuffer[nextOutBufferIndex++] = (byte) (((byte) (s >> 8)) & 0xff);
358                                 outBuffer[nextOutBufferIndex++] = (byte) ((byte) (s & 0xff));
359                         } else {
360                                 outBuffer[nextOutBufferIndex++] = (byte) ((byte) (s & 0xff));
361                                 outBuffer[nextOutBufferIndex++] = (byte) (((byte) (s >> 8)) & 0xff);
362                         }
363                 }
364
365                 public void Append (short s)
366                 {
367                         SendIfFull (sizeof (short));
368                         AppendInternal (s);
369                 }
370
371                 public void Append (ushort s)
372                 {
373                         SendIfFull (sizeof (short));
374                         AppendInternal ((short) s);
375                 }
376
377                 private void AppendInternal (int i)
378                 {
379                         if (!lsb) {
380                                 AppendInternal ((short) (((short) (i >> 16)) & 0xffff));
381                                 AppendInternal ((short) ((short) (i & 0xffff)));
382                         } else {
383                                 AppendInternal ((short) ((short) (i & 0xffff)));
384                                 AppendInternal ((short) (((short) (i >> 16)) & 0xffff));
385                         }                               
386                 }
387
388                 public void Append (int i)
389                 {
390                         SendIfFull (sizeof (int));
391                         AppendInternal (i);
392                 }
393
394                 public void Append (string s)
395                 {
396                         if (tdsVersion < TdsVersion.tds70) { 
397                                 Append (encoder.GetBytes (s));
398                         } else {
399                                 int cindex = 0, index;
400                                 int ssize = sizeof (short);
401                                 int lenToWrite = s.Length * ssize;
402                                 // if nextOutBufferLength points to the last buffer in outBuffer, 
403                                 // we would get a DivisionByZero while calculating remBufLen
404                                 if (outBufferLength - nextOutBufferIndex < ssize)
405                                         SendIfFull (ssize);
406                                 
407                                 int remBufLen = outBufferLength - nextOutBufferIndex;
408                                 int count = lenToWrite/remBufLen;
409                                 
410                                 if (lenToWrite % remBufLen > 0)
411                                         count++;
412                         
413                                 for (int i = 0; i < count; i++) {
414                                         index = System.Math.Min (remBufLen/ssize, lenToWrite/ssize);
415                                         for (int j = 0; j < index*ssize; j+=2, cindex++)
416                                                 AppendInternal ((short)s[cindex]);
417                                         
418                                         lenToWrite -= index*ssize;
419                                         // Just make sure to flush the buffer
420                                         SendIfFull ((lenToWrite+1)*ssize);
421                                 }
422                         }
423                 }       
424
425                 // Appends with padding
426                 public byte[] Append (string s, int len, byte pad)
427                 {
428                         if (s == null)
429                                 return new byte[0];
430
431                         byte[] result = encoder.GetBytes (s);
432                         Append (result, len, pad);
433                         return result;
434                 }
435
436                 public void Append (double value)
437                 {
438                         if (!lsb)
439                                 Append (Swap (BitConverter.GetBytes (value)), sizeof(double), (byte)0);
440                         else
441                                 Append (BitConverter.GetBytes (value), sizeof(double), (byte)0);
442                 }
443
444                 public void Append (float value)
445                 {
446                         if (!lsb)
447                                 Append (Swap (BitConverter.GetBytes (value)), sizeof(float), (byte)0);
448                         else
449                                 Append (BitConverter.GetBytes (value), sizeof(float), (byte)0);
450                 }
451
452                 public void Append (long l)
453                 {
454                         SendIfFull (sizeof (long));
455                         if (!lsb) {
456                                 AppendInternal ((int) (((int) (l >> 32)) & 0xffffffff));
457                                 AppendInternal ((int) ((int) (l & 0xffffffff)));
458                         } else {
459                                 AppendInternal ((int) ((int) (l & 0xffffffff)));
460                                 AppendInternal ((int) (((int) (l >> 32)) & 0xffffffff));
461                         }                               
462                 }
463
464                 public void Append (decimal d, int bytes)
465                 {
466                         int[] arr = Decimal.GetBits (d);
467                         byte sign =  (d > 0 ? (byte)1 : (byte)0);
468                         SendIfFull (bytes);
469                         Append (sign) ;
470                         AppendInternal (arr[0]);
471                         AppendInternal (arr[1]);
472                         AppendInternal (arr[2]);
473                         AppendInternal ((int)0);
474                 }
475
476                 public void Close ()
477                 {
478                         if (stream == null)
479                                 return;
480
481                         connReset = false;
482                         socket = null;
483                         try {
484                                 stream.Close ();
485                         } catch {
486                         }
487                         stream = null;
488                 }
489
490                 public bool IsConnected () 
491                 {
492                         return socket != null && socket.Connected && !(socket.Poll (0, SelectMode.SelectRead) && socket.Available == 0);
493                 }
494                 
495                 public byte GetByte ()
496                 {
497                         byte result;
498
499                         if (inBufferIndex >= inBufferLength) {
500                                 // out of data, read another physical packet.
501                                 GetPhysicalPacket ();
502                         }
503                         result = inBuffer[inBufferIndex++];
504                         return result;
505                 }
506
507                 public byte[] GetBytes (int len, bool exclusiveBuffer)
508                 {
509                         byte[] result = null;
510                         int i;
511
512                         // Do not keep an internal result buffer larger than 16k.
513                         // This would unnecessarily use up memory.
514                         if (exclusiveBuffer || len > 16384)
515                                 result = new byte[len];
516                         else
517                         {
518                                 if (resBuffer.Length < len)
519                                         resBuffer = new byte[len];
520                                 result = resBuffer;
521                         }
522
523                         for (i = 0; i<len; )
524                         {
525                                 if (inBufferIndex >= inBufferLength)
526                                         GetPhysicalPacket ();
527
528                                 int avail = inBufferLength - inBufferIndex;
529                                 avail = avail>len-i ? len-i : avail;
530
531                                 Buffer.BlockCopy (inBuffer, inBufferIndex, result, i, avail);
532                                 i += avail;
533                                 inBufferIndex += avail;
534                         }
535
536                         return result;
537                 }
538
539                 public string GetString (int len, Encoding enc)
540                 {
541                         if (tdsVersion >= TdsVersion.tds70) 
542                                 return GetString (len, true, null);
543                         else
544                                 return GetString (len, false, null);
545                 }
546                 
547                 public string GetString (int len)
548                 {
549                         if (tdsVersion >= TdsVersion.tds70) 
550                                 return GetString (len, true);
551                         else
552                                 return GetString (len, false);
553                 }
554
555                 public string GetString (int len, bool wide, Encoding enc)
556                 {
557                         if (wide) {
558                                 char[] chars = new char[len];
559                                 for (int i = 0; i < len; ++i) {
560                                         int lo = ((byte) GetByte ()) & 0xFF;
561                                         int hi = ((byte) GetByte ()) & 0xFF;
562                                         chars[i] = (char) (lo | ( hi << 8));
563                                 }
564                                 return new String (chars);
565                         }
566                         else {
567                                 byte[] result = new byte[len];
568                                 Array.Copy (GetBytes (len, false), result, len);
569                                 // Use the passed encoder, if available
570                                 if (enc != null)
571                                         return (enc.GetString (result));
572                                 else
573                                         return (encoder.GetString (result));
574                         }
575                 }
576                 
577                 public string GetString (int len, bool wide)
578                 {
579                         return GetString (len, wide, null);
580                 }
581
582                 public int GetNetShort ()
583                 {
584                         byte[] tmp = new byte[2];
585                         tmp[0] = GetByte ();
586                         tmp[1] = GetByte ();
587                         return Ntohs (tmp, 0);
588                 }
589
590                 public short GetTdsShort ()
591                 {
592                         byte[] input = new byte[2];
593
594                         for (int i = 0; i < 2; i += 1)
595                                 input[i] = GetByte ();
596                         if(!BitConverter.IsLittleEndian)
597                                 return (BitConverter.ToInt16 (Swap (input), 0));
598                         else
599                                 return (BitConverter.ToInt16 (input, 0));
600                 }
601
602
603                 public int GetTdsInt ()
604                 {
605                         byte[] input = new byte[4];
606                         for (int i = 0; i < 4; i += 1) {
607                                 input[i] = GetByte ();
608                         }
609                         if(!BitConverter.IsLittleEndian)
610                                 return (BitConverter.ToInt32 (Swap (input), 0));
611                         else
612                                 return (BitConverter.ToInt32 (input, 0));
613                 }
614
615                 public long GetTdsInt64 ()
616                 {
617                         byte[] input = new byte[8];
618                         for (int i = 0; i < 8; i += 1)
619                                 input[i] = GetByte ();
620                         if(!BitConverter.IsLittleEndian)
621                                 return (BitConverter.ToInt64 (Swap (input), 0));
622                         else
623                                 return (BitConverter.ToInt64 (input, 0));
624                 }
625
626                 private void GetPhysicalPacket ()
627                 {
628                         int dataLength = GetPhysicalPacketHeader ();
629                         GetPhysicalPacketData (dataLength);
630                 }
631
632                 int Read (byte [] buffer, int offset, int count)
633                 {
634                         try {
635                                 return stream.Read (buffer, offset, count);
636                         } catch {
637                                 socket = null;
638                                 stream.Close ();
639                                 throw;
640                         }
641                 }
642
643                 private int GetPhysicalPacketHeader ()
644                 {
645                         int nread = 0;
646
647                         int n;
648                         // read the header
649                         while (nread < 8) {
650                                 n = Read (tmpBuf, nread, 8 - nread);
651                                 if (n <= 0) {
652                                         socket = null;
653                                         stream.Close ();
654                                         throw new IOException (n == 0 ? "Connection lost" : "Connection error");
655                                 }
656                                 nread += n;
657                         }
658
659                         TdsPacketType packetType = (TdsPacketType) tmpBuf[0];
660                         if (packetType != TdsPacketType.Logon && packetType != TdsPacketType.Query && packetType != TdsPacketType.Reply) 
661                         {
662                                 throw new Exception (String.Format ("Unknown packet type {0}", tmpBuf[0]));
663                         }
664
665                         // figure out how many bytes are remaining in this packet.
666                         int len = Ntohs (tmpBuf, 2) - 8;
667                         if (len >= inBuffer.Length) 
668                                 inBuffer = new byte[len];
669
670                         if (len < 0) {
671                                 throw new Exception (String.Format ("Confused by a length of {0}", len));
672                         }
673                         
674                         return len;
675
676                 }
677                 
678                 private void GetPhysicalPacketData (int length)
679                 {
680                         // now get the data
681                         int nread = 0;
682                         int n;
683
684                         while (nread < length) {
685                                 n = Read (inBuffer, nread, length - nread);
686                                 if (n <= 0) {
687                                         socket = null;
688                                         stream.Close ();
689                                         throw new IOException (n == 0 ? "Connection lost" : "Connection error");
690                                 }
691                                 nread += n;
692                         }
693
694                         packetsReceived++;
695
696                         // adjust the bookkeeping info about the incoming buffer
697                         inBufferLength = length;
698                         inBufferIndex = 0;
699                 }
700                 
701
702                 private static int Ntohs (byte[] buf, int offset)
703                 {
704                         int lo = ((int) buf[offset + 1] & 0xff);
705                         int hi = (((int) buf[offset] & 0xff ) << 8);
706
707                         return hi | lo;
708                         // return an int since we really want an _unsigned_
709                 }               
710
711                 public byte Peek ()
712                 {
713                         // If out of data, read another physical packet.
714                         if (inBufferIndex >= inBufferLength)
715                                 GetPhysicalPacket ();
716
717                         return inBuffer[inBufferIndex];
718                 }
719
720                 public bool Poll (int seconds, SelectMode selectMode)
721                 {
722                         return Poll (socket, seconds, selectMode);
723                 }
724
725                 private bool Poll (Socket s, int seconds, SelectMode selectMode)
726                 {
727                         long uSeconds = seconds * 1000000;
728                         bool bState = false;
729
730                         while (uSeconds > (long) Int32.MaxValue) {
731                                 bState = s.Poll (Int32.MaxValue, selectMode);
732                                 if (bState) 
733                                         return true;
734                                 uSeconds -= Int32.MaxValue;
735                         }
736                         return s.Poll ((int) uSeconds, selectMode);
737                 }
738
739                 internal void ResizeOutBuf (int newSize)
740                 {
741                         if (newSize != outBufferLength) {
742                                 byte[] newBuf = new byte [newSize];
743                                 Buffer.BlockCopy (outBuffer, 0, newBuf, 0, newSize);
744                                 outBufferLength = newSize;
745                                 outBuffer = newBuf;
746                         }
747                 }
748
749                 public bool ResetConnection {
750                         get { return connReset; }
751                         set { connReset = value; }
752                 }
753
754                 public void SendPacket ()
755                 {
756                         // Reset connection flag is only valid for SQLBatch/RPC/DTC messages
757                         if (packetType != TdsPacketType.Query && packetType != TdsPacketType.RPC)
758                                 connReset = false;
759                         
760                         SendPhysicalPacket (true);
761                         nextOutBufferIndex = 0;
762                         packetType = TdsPacketType.None;
763                         // Reset connection-reset flag to false - as any exception would anyway close 
764                         // the whole connection
765                         connReset = false;
766                         packetsSent = 1;
767                 }
768                 
769                 private void SendPhysicalPacket (bool isLastSegment)
770                 {
771                         if (nextOutBufferIndex > headerLength || packetType == TdsPacketType.Cancel) {
772                                 byte status =  (byte) ((isLastSegment ? 0x01 : 0x00) | (connReset ? 0x08 : 0x00)); 
773                                 // packet type
774                                 Store (0, (byte) packetType);
775                                 Store (1, status);
776                                 Store (2, (short) nextOutBufferIndex );
777                                 Store (4, (byte) 0);
778                                 Store (5, (byte) 0);
779                                 if (tdsVersion >= TdsVersion.tds70)
780                                         Store (6, (byte) packetsSent);
781                                 else    
782                                         Store (6, (byte) 0);
783                                 Store (7, (byte) 0);
784
785                                 stream.Write (outBuffer, 0, nextOutBufferIndex);
786                                 stream.Flush ();
787                                 packetsSent++;
788                         }
789                 }
790                 
791                 public void Skip (long i)
792                 {
793                         for ( ; i > 0; i--)
794                                 GetByte ();
795                 }
796
797                 public void StartPacket (TdsPacketType type)
798                 {
799                         if (type != TdsPacketType.Cancel && inBufferIndex != inBufferLength)
800                                 inBufferIndex = inBufferLength;
801
802                         packetType = type;
803                         nextOutBufferIndex = headerLength;
804                 }
805
806                 private void Store (int index, byte value)
807                 {
808                         outBuffer[index] = value;
809                 }               
810
811                 private void Store (int index, short value)
812                 {
813                         outBuffer[index] = (byte) (((byte) (value >> 8)) & 0xff);
814                         outBuffer[index + 1] = (byte) (((byte) (value >> 0)) & 0xff);
815                 }
816
817                 #endregion // Methods
818 #if NET_2_0
819                 #region Async Methods
820
821                 public IAsyncResult BeginReadPacket (AsyncCallback callback, object stateObject)
822                 {
823                         TdsAsyncResult ar = new TdsAsyncResult (callback, stateObject);
824
825                         stream.BeginRead (tmpBuf, 0, 8, new AsyncCallback(OnReadPacketCallback), ar);
826                         return ar;
827                 }
828                 
829                 /// <returns>Packet size in bytes</returns>
830                 public int EndReadPacket (IAsyncResult ar)
831                 {
832                         if (!ar.IsCompleted)
833                                 ar.AsyncWaitHandle.WaitOne ();
834                         return (int) ((TdsAsyncResult) ar).ReturnValue;
835                 }
836                 
837
838                 public void OnReadPacketCallback (IAsyncResult socketAsyncResult)
839                 {
840                         TdsAsyncResult ar = (TdsAsyncResult) socketAsyncResult.AsyncState;
841                         int nread = stream.EndRead (socketAsyncResult);
842                         int n;
843                         
844                         while (nread < 8) {
845                                 n = Read (tmpBuf, nread, 8 - nread);
846                                 if (n <= 0) {
847                                         socket = null;
848                                         stream.Close ();
849                                         throw new IOException (n == 0 ? "Connection lost" : "Connection error");
850                                 }
851                                 nread += n;
852                         }
853
854                         TdsPacketType packetType = (TdsPacketType) tmpBuf[0];
855                         if (packetType != TdsPacketType.Logon && packetType != TdsPacketType.Query && packetType != TdsPacketType.Reply) 
856                         {
857                                 throw new Exception (String.Format ("Unknown packet type {0}", tmpBuf[0]));
858                         }
859
860                         // figure out how many bytes are remaining in this packet.
861                         int len = Ntohs (tmpBuf, 2) - 8;
862
863                         if (len >= inBuffer.Length) 
864                                 inBuffer = new byte[len];
865
866                         if (len < 0) {
867                                 throw new Exception (String.Format ("Confused by a length of {0}", len));
868                         }
869
870                         GetPhysicalPacketData (len);
871                         int value = len + 8;
872                         ar.ReturnValue = ((object)value); // packet size
873                         ar.MarkComplete ();
874                 }
875                 
876                 #endregion // Async Methods
877 #endif // NET_2_0
878
879         }
880
881 }