TdsParserStateObject.cs 169 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754
  1. //------------------------------------------------------------------------------
  2. // <copyright file="TdsParserStateObject.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data.SqlClient {
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Data.Common;
  12. using System.Data.ProviderBase;
  13. using System.Data.Sql;
  14. using System.Data.SqlTypes;
  15. using System.Diagnostics;
  16. using System.Globalization;
  17. using System.Linq;
  18. using System.Runtime.CompilerServices;
  19. using System.Runtime.InteropServices;
  20. using System.Runtime.ConstrainedExecution;
  21. using System.Threading;
  22. using System.Threading.Tasks;
  23. using System.Security;
  24. using System.Text;
  25. sealed internal class LastIOTimer {
  26. internal long _value;
  27. }
  28. sealed internal class TdsParserStateObject {
  29. const int AttentionTimeoutSeconds = 5;
  30. // Ticks to consider a connection "good" after a successful I/O (10,000 ticks = 1 ms)
  31. // The resolution of the timer is typically in the range 10 to 16 milliseconds according to msdn.
  32. // We choose a value that is smaller than the likely timer resolution, but
  33. // large enough to ensure that check connection execution will be 0.1% or less
  34. // of very small open, query, close loops.
  35. private const long CheckConnectionWindow = 50000;
  36. private static int _objectTypeCount; // Bid counter
  37. internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
  38. internal int ObjectID {
  39. get {
  40. return _objectID;
  41. }
  42. }
  43. private readonly TdsParser _parser; // TdsParser pointer
  44. private SNIHandle _sessionHandle = null; // the SNI handle we're to work on
  45. private readonly WeakReference _owner = new WeakReference(null); // the owner of this session, used to track when it's been orphaned
  46. internal SqlDataReader.SharedState _readerState; // susbset of SqlDataReader state (if it is the owner) necessary for parsing abandoned results in TDS
  47. private int _activateCount; // 0 when we're in the pool, 1 when we're not, all others are an error
  48. // Two buffers exist in tdsparser, an in buffer and an out buffer. For the out buffer, only
  49. // one bookkeeping variable is needed, the number of bytes used in the buffer. For the in buffer,
  50. // three variables are actually needed. First, we need to record from the netlib how many bytes it
  51. // read from the netlib, this variable is _inBytesRead. Then, we need to also keep track of how many
  52. // bytes we have used as we consume the bytes from the buffer, that variable is _inBytesUsed. Third,
  53. // we need to keep track of how many bytes are left in the packet, so that we know when we have reached
  54. // the end of the packet and so we need to consume the next header. That variable is _inBytesPacket.
  55. // Header length constants
  56. internal readonly int _inputHeaderLen = TdsEnums.HEADER_LEN;
  57. internal readonly int _outputHeaderLen = TdsEnums.HEADER_LEN;
  58. // Out buffer variables
  59. internal byte[] _outBuff; // internal write buffer - initialize on login
  60. internal int _outBytesUsed = TdsEnums.HEADER_LEN; // number of bytes used in internal write buffer -
  61. // - initialize past header
  62. // In buffer variables
  63. private byte[] _inBuff; // internal read buffer - initialize on login
  64. internal int _inBytesUsed = 0; // number of bytes used in internal read buffer
  65. internal int _inBytesRead = 0; // number of bytes read into internal read buffer
  66. internal int _inBytesPacket = 0; // number of bytes left in packet
  67. // Packet state variables
  68. internal byte _outputMessageType = 0; // tds header type
  69. internal byte _messageStatus; // tds header status
  70. internal byte _outputPacketNumber = 1; // number of packets sent to server
  71. // in message - start at 1 per ramas
  72. internal bool _pendingData = false;
  73. internal volatile bool _fResetEventOwned = false; // ResetEvent serializing call to sp_reset_connection
  74. internal volatile bool _fResetConnectionSent = false; // For multiple packet execute
  75. internal bool _errorTokenReceived = false; // Keep track of whether an error was received for the result.
  76. // This is reset upon each done token - there can be
  77. internal bool _bulkCopyOpperationInProgress = false; // Set to true during bulk copy and used to turn toggle write timeouts.
  78. internal bool _bulkCopyWriteTimeout = false; // Set to trun when _bulkCopyOpeperationInProgress is trun and write timeout happens
  79. // SNI variables // multiple resultsets in one batch.
  80. private SNIPacket _sniPacket = null; // Will have to re-vamp this for MARS
  81. internal SNIPacket _sniAsyncAttnPacket = null; // Packet to use to send Attn
  82. private WritePacketCache _writePacketCache = new WritePacketCache(); // Store write packets that are ready to be re-used
  83. private Dictionary<IntPtr, SNIPacket> _pendingWritePackets = new Dictionary<IntPtr,SNIPacket>(); // Stores write packets that have been sent to SNI, but have not yet finished writing (i.e. we are waiting for SNI's callback)
  84. private object _writePacketLockObject = new object(); // Used to synchronize access to _writePacketCache and _pendingWritePackets
  85. // Async variables
  86. private GCHandle _gcHandle; // keeps this object alive until we're closed.
  87. private int _pendingCallbacks; // we increment this before each async read/write call and decrement it in the callback. We use this to determine when to release the GcHandle...
  88. // Timeout variables
  89. private long _timeoutMilliseconds;
  90. private long _timeoutTime; // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire
  91. internal volatile bool _attentionSent = false; // true if we sent an Attention to the server
  92. internal bool _attentionReceived = false; // NOTE: Received is not volatile as it is only ever accessed\modified by TryRun its callees (i.e. single threaded access)
  93. internal volatile bool _attentionSending = false;
  94. internal bool _internalTimeout = false; // an internal timeout occured
  95. private readonly LastIOTimer _lastSuccessfulIOTimer;
  96. // secure password information to be stored
  97. // At maximum number of secure string that need to be stored is two; one for login password and the other for new change password
  98. private SecureString[] _securePasswords = new SecureString[2] {null, null};
  99. private int[] _securePasswordOffsetsInBuffer = new int[2];
  100. // This variable is used to track whether another thread has requested a cancel. The
  101. // synchronization points are
  102. // On the user's execute thread:
  103. // 1) the first packet write
  104. // 2) session close - return this stateObj to the session pool
  105. // On cancel thread we only have the cancel call.
  106. // Currently all access to this variable is inside a lock, though I hope to limit that in the
  107. // future. The state diagram is:
  108. // 1) pre first packet write, if cancel is requested, set variable so exception is triggered
  109. // on user thread when first packet write is attempted
  110. // 2) post first packet write, but before session return - a call to cancel will send an
  111. // attention to the server
  112. // 3) post session close - no attention is allowed
  113. private bool _cancelled;
  114. private const int _waitForCancellationLockPollTimeout = 100;
  115. // This variable is used to prevent sending an attention by another thread that is not the
  116. // current owner of the stateObj. I currently do not know how this can happen. Mark added
  117. // the code but does not remember either. At some point, we need to research killing this
  118. // logic.
  119. private volatile int _allowObjectID;
  120. internal bool _hasOpenResult = false;
  121. // Cache the transaction for which this command was executed so upon completion we can
  122. // decrement the appropriate result count.
  123. internal SqlInternalTransaction _executedUnderTransaction = null;
  124. // TDS stream processing variables
  125. internal ulong _longlen; // plp data length indicator
  126. internal ulong _longlenleft; // Length of data left to read (64 bit lengths)
  127. internal int[] _decimalBits = null; // scratch buffer for decimal/numeric data
  128. internal byte[] _bTmp = new byte[TdsEnums.YUKON_HEADER_LEN]; // Scratch buffer for misc use
  129. internal int _bTmpRead = 0; // Counter for number of temporary bytes read
  130. internal Decoder _plpdecoder = null; // Decoder object to process plp character data
  131. internal bool _accumulateInfoEvents= false; // TRUE - accumulate info messages during TdsParser.Run, FALSE - fire them
  132. internal List<SqlError> _pendingInfoEvents = null;
  133. internal byte[] _bLongBytes = null; // scratch buffer to serialize Long values (8 bytes).
  134. internal byte[] _bIntBytes = null; // scratch buffer to serialize Int values (4 bytes).
  135. internal byte[] _bShortBytes = null; // scratch buffer to serialize Short values (2 bytes).
  136. internal byte[] _bDecimalBytes = null; // scratch buffer to serialize decimal values (17 bytes).
  137. //
  138. // DO NOT USE THIS BUFFER FOR OTHER THINGS.
  139. // ProcessHeader can be called ANYTIME while doing network reads.
  140. private byte[] _partialHeaderBuffer = new byte[TdsEnums.HEADER_LEN]; // Scratch buffer for ProcessHeader
  141. internal int _partialHeaderBytesRead = 0;
  142. //
  143. internal _SqlMetaDataSet _cleanupMetaData = null;
  144. internal _SqlMetaDataSetCollection _cleanupAltMetaDataSetArray = null;
  145. // Used for blanking out password in trace.
  146. internal int _tracePasswordOffset = 0;
  147. internal int _tracePasswordLength = 0;
  148. internal int _traceChangePasswordOffset = 0;
  149. internal int _traceChangePasswordLength = 0;
  150. internal bool _receivedColMetaData; // Used to keep track of when to fire StatementCompleted event.
  151. private SniContext _sniContext=SniContext.Undefined;
  152. #if DEBUG
  153. private SniContext _debugOnlyCopyOfSniContext=SniContext.Undefined;
  154. #endif
  155. private bool _bcpLock = false;
  156. // Null bitmap compression (NBC) information for the current row
  157. private NullBitmap _nullBitmapInfo;
  158. // Async
  159. internal TaskCompletionSource<object> _networkPacketTaskSource;
  160. private Timer _networkPacketTimeout;
  161. internal bool _syncOverAsync = true;
  162. private bool _snapshotReplay = false;
  163. private StateSnapshot _snapshot;
  164. internal ExecutionContext _executionContext;
  165. internal bool _asyncReadWithoutSnapshot = false;
  166. #if DEBUG
  167. // Used to override the assert than ensures that the stacktraces on subsequent replays are the same
  168. // This is useful is you are purposefully running the replay from a different thread (e.g. during SqlDataReader.Close)
  169. internal bool _permitReplayStackTraceToDiffer = false;
  170. // Used to indicate that the higher level object believes that this stateObj has enough data to complete an operation
  171. // If this stateObj has to read, then it will raise an assert
  172. internal bool _shouldHaveEnoughData = false;
  173. #endif
  174. // local exceptions to cache warnings and errors
  175. internal SqlErrorCollection _errors;
  176. internal SqlErrorCollection _warnings;
  177. internal object _errorAndWarningsLock = new object();
  178. private bool _hasErrorOrWarning = false;
  179. // local exceptions to cache warnings and errors that occured prior to sending attention
  180. internal SqlErrorCollection _preAttentionErrors;
  181. internal SqlErrorCollection _preAttentionWarnings;
  182. volatile private TaskCompletionSource<object> _writeCompletionSource = null;
  183. volatile private int _asyncWriteCount = 0;
  184. volatile private Exception _delayedWriteAsyncCallbackException = null; // set by write async callback if completion source is not yet created
  185. // _readingcount is incremented when we are about to read.
  186. // We check the parser state afterwards.
  187. // When the read is completed, we decrement it before handling errors
  188. // as the error handling may end up calling Dispose.
  189. int _readingCount;
  190. // Test hooks
  191. #if DEBUG
  192. // This is a test hook to enable testing of the retry paths.
  193. // When set to true, almost every possible retry point will be attempted.
  194. // This will drastically impact performance.
  195. //
  196. // Sample code to enable:
  197. //
  198. // Type type = typeof(SqlDataReader).Assembly.GetType("System.Data.SqlClient.TdsParserStateObject");
  199. // System.Reflection.FieldInfo field = type.GetField("_forceAllPends", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
  200. // if (field != null) {
  201. // field.SetValue(null, true);
  202. // }
  203. //
  204. internal static bool _forceAllPends = false;
  205. // set this while making a call that should not block.
  206. // instead of blocking it will fail.
  207. internal static bool _failAsyncPends = false;
  208. // If this is set and an async read is made, then
  209. // we will switch to syncOverAsync mode for the
  210. // remainder of the async operation.
  211. internal static bool _forceSyncOverAsyncAfterFirstPend = false;
  212. // Requests to send attention will be ignored when _skipSendAttention is true.
  213. // This is useful to simulate circumstances where timeouts do not recover.
  214. internal static bool _skipSendAttention = false;
  215. // Prevents any pending read from completing until the user signals it using
  216. // CompletePendingReadWithSuccess() or CompletePendingReadWithFailure(int errorCode) in SqlCommand\SqlDataReader
  217. internal static bool _forcePendingReadsToWaitForUser;
  218. internal TaskCompletionSource<object> _realNetworkPacketTaskSource = null;
  219. // Set to true to enable checking the call stacks match when packet retry occurs.
  220. internal static bool _checkNetworkPacketRetryStacks;
  221. #endif
  222. //////////////////
  223. // Constructors //
  224. //////////////////
  225. internal TdsParserStateObject(TdsParser parser) {
  226. // Construct a physical connection
  227. Debug.Assert(null != parser, "no parser?");
  228. _parser = parser;
  229. // For physical connection, initialize to default login packet size.
  230. SetPacketSize(TdsEnums.DEFAULT_LOGIN_PACKET_SIZE);
  231. // we post a callback that represents the call to dispose; once the
  232. // object is disposed, the next callback will cause the GC Handle to
  233. // be released.
  234. IncrementPendingCallbacks();
  235. _lastSuccessfulIOTimer = new LastIOTimer();
  236. }
  237. internal TdsParserStateObject(TdsParser parser, SNIHandle physicalConnection, bool async) {
  238. // Construct a MARS session
  239. Debug.Assert(null != parser, "no parser?");
  240. _parser = parser;
  241. SniContext=SniContext.Snix_GetMarsSession;
  242. Debug.Assert(null != _parser._physicalStateObj, "no physical session?");
  243. Debug.Assert(null != _parser._physicalStateObj._inBuff, "no in buffer?");
  244. Debug.Assert(null != _parser._physicalStateObj._outBuff, "no out buffer?");
  245. Debug.Assert(_parser._physicalStateObj._outBuff.Length ==
  246. _parser._physicalStateObj._inBuff.Length, "Unexpected unequal buffers.");
  247. // Determine packet size based on physical connection buffer lengths.
  248. SetPacketSize(_parser._physicalStateObj._outBuff.Length);
  249. SNINativeMethodWrapper.ConsumerInfo myInfo = CreateConsumerInfo(async);
  250. _sessionHandle = new SNIHandle(myInfo, physicalConnection);
  251. if (_sessionHandle.Status != TdsEnums.SNI_SUCCESS) {
  252. AddError(parser.ProcessSNIError(this));
  253. ThrowExceptionAndWarning();
  254. }
  255. // we post a callback that represents the call to dispose; once the
  256. // object is disposed, the next callback will cause the GC Handle to
  257. // be released.
  258. IncrementPendingCallbacks();
  259. _lastSuccessfulIOTimer = parser._physicalStateObj._lastSuccessfulIOTimer;
  260. }
  261. ////////////////
  262. // Properties //
  263. ////////////////
  264. // BcpLock - use to lock this object if there is a potential risk of using this object
  265. // between tds packets
  266. internal bool BcpLock {
  267. get {
  268. return _bcpLock;
  269. }
  270. set {
  271. _bcpLock = value;
  272. }
  273. }
  274. #if DEBUG
  275. internal SniContext DebugOnlyCopyOfSniContext {
  276. get {
  277. return _debugOnlyCopyOfSniContext;
  278. }
  279. }
  280. #endif
  281. internal SNIHandle Handle {
  282. get {
  283. return _sessionHandle;
  284. }
  285. }
  286. internal bool HasOpenResult {
  287. get {
  288. return _hasOpenResult;
  289. }
  290. }
  291. #if DEBUG
  292. internal void InvalidateDebugOnlyCopyOfSniContext() {
  293. _debugOnlyCopyOfSniContext = SniContext.Undefined;
  294. }
  295. #endif
  296. internal bool IsOrphaned {
  297. get {
  298. Debug.Assert((0 == _activateCount && !_owner.IsAlive) // in pool
  299. || (1 == _activateCount && _owner.IsAlive && _owner.Target != null)
  300. || (1 == _activateCount && !_owner.IsAlive), "Unknown state on TdsParserStateObject.IsOrphaned!");
  301. return (0 != _activateCount && !_owner.IsAlive);
  302. }
  303. }
  304. internal object Owner {
  305. set {
  306. Debug.Assert(value == null || !_owner.IsAlive || ((value is SqlDataReader) && (((SqlDataReader)value).Command == _owner.Target)), "Should not be changing the owner of an owned stateObj");
  307. SqlDataReader reader=value as SqlDataReader;
  308. if (reader == null) {
  309. _readerState = null;
  310. }
  311. else {
  312. _readerState = reader._sharedState;
  313. }
  314. _owner.Target = value;
  315. }
  316. }
  317. internal bool HasOwner {
  318. get {
  319. return _owner.IsAlive;
  320. }
  321. }
  322. internal TdsParser Parser {
  323. get {
  324. return _parser;
  325. }
  326. }
  327. internal SniContext SniContext {
  328. get {
  329. return _sniContext;
  330. }
  331. set {
  332. _sniContext = value;
  333. #if DEBUG
  334. _debugOnlyCopyOfSniContext = value;
  335. #endif
  336. }
  337. }
  338. internal UInt32 Status {
  339. get {
  340. if (_sessionHandle != null) {
  341. return _sessionHandle.Status;
  342. }
  343. else { // SQL BU DT 395431.
  344. return TdsEnums.SNI_UNINITIALIZED;
  345. }
  346. }
  347. }
  348. internal bool TimeoutHasExpired {
  349. get {
  350. Debug.Assert(0 == _timeoutMilliseconds || 0 == _timeoutTime, "_timeoutTime hasn't been reset");
  351. return TdsParserStaticMethods.TimeoutHasExpired(_timeoutTime);
  352. }
  353. }
  354. internal long TimeoutTime {
  355. get {
  356. if (0 != _timeoutMilliseconds) {
  357. _timeoutTime = TdsParserStaticMethods.GetTimeout(_timeoutMilliseconds);
  358. _timeoutMilliseconds = 0;
  359. }
  360. return _timeoutTime;
  361. }
  362. set {
  363. _timeoutMilliseconds = 0;
  364. _timeoutTime = value;
  365. }
  366. }
  367. internal int GetTimeoutRemaining() {
  368. int remaining;
  369. if (0 != _timeoutMilliseconds) {
  370. remaining = (int)Math.Min((long)Int32.MaxValue, _timeoutMilliseconds);
  371. _timeoutTime = TdsParserStaticMethods.GetTimeout(_timeoutMilliseconds);
  372. _timeoutMilliseconds = 0;
  373. }
  374. else {
  375. remaining = TdsParserStaticMethods.GetTimeoutMilliseconds(_timeoutTime);
  376. }
  377. return remaining;
  378. }
  379. internal bool TryStartNewRow(bool isNullCompressed, int nullBitmapColumnsCount = 0) {
  380. Debug.Assert(!isNullCompressed || nullBitmapColumnsCount > 0, "Null-Compressed row requires columns count");
  381. if (_snapshot != null) {
  382. _snapshot.CloneNullBitmapInfo();
  383. }
  384. // initialize or unset null bitmap information for the current row
  385. if (isNullCompressed){
  386. // assert that NBCROW is not in use by Yukon or before
  387. Debug.Assert(_parser.IsKatmaiOrNewer, "NBCROW is sent by pre-Katmai server");
  388. if (!_nullBitmapInfo.TryInitialize(this, nullBitmapColumnsCount)) {
  389. return false;
  390. }
  391. }
  392. else {
  393. _nullBitmapInfo.Clean();
  394. }
  395. return true;
  396. }
  397. internal bool IsRowTokenReady() {
  398. // Removing one byte since TryReadByteArray\TryReadByte will aggressively read the next packet if there is no data left - so we need to ensure there is a spare byte
  399. int bytesRemaining = Math.Min(_inBytesPacket, _inBytesRead - _inBytesUsed) - 1;
  400. if (bytesRemaining > 0) {
  401. if (_inBuff[_inBytesUsed] == TdsEnums.SQLROW) {
  402. // At a row token, so we're ready
  403. return true;
  404. }
  405. else if (_inBuff[_inBytesUsed] == TdsEnums.SQLNBCROW) {
  406. // NBC row token, ensure that we have enough data for the bitmap
  407. // SQLNBCROW + Null Bitmap (copied from NullBitmap.TryInitialize)
  408. int bytesToRead = 1 + (_cleanupMetaData.Length + 7) / 8;
  409. return (bytesToRead <= bytesRemaining);
  410. }
  411. }
  412. // No data left, or not at a row token
  413. return false;
  414. }
  415. internal bool IsNullCompressionBitSet(int columnOrdinal) {
  416. return _nullBitmapInfo.IsGuaranteedNull(columnOrdinal);
  417. }
  418. private struct NullBitmap {
  419. private byte[] _nullBitmap;
  420. private int _columnsCount; // set to 0 if not used or > 0 for NBC rows
  421. internal bool TryInitialize(TdsParserStateObject stateObj, int columnsCount) {
  422. _columnsCount = columnsCount;
  423. // 1-8 columns need 1 byte
  424. // 9-16: 2 bytes, and so on
  425. int bitmapArrayLength = (columnsCount + 7) / 8;
  426. // allow reuse of previously allocated bitmap
  427. if (_nullBitmap == null || _nullBitmap.Length != bitmapArrayLength) {
  428. _nullBitmap = new byte[bitmapArrayLength];
  429. }
  430. // read the null bitmap compression information from TDS
  431. if (!stateObj.TryReadByteArray(_nullBitmap, 0, _nullBitmap.Length)) {
  432. return false;
  433. }
  434. if (Bid.TraceOn) {
  435. Bid.Trace("<sc.TdsParserStateObject.NullBitmap.Initialize|INFO|ADV> %d#, NBCROW bitmap received, column count = %d\n", stateObj.ObjectID, columnsCount);
  436. Bid.TraceBin("<sc.TdsParserStateObject.NullBitmap.Initialize|INFO|ADV> NBCROW bitmap data: ", _nullBitmap, (UInt16)_nullBitmap.Length);
  437. }
  438. return true;
  439. }
  440. internal bool ReferenceEquals(NullBitmap obj) {
  441. return object.ReferenceEquals(_nullBitmap, obj._nullBitmap);
  442. }
  443. internal NullBitmap Clone()
  444. {
  445. NullBitmap newBitmap = new NullBitmap();
  446. newBitmap._nullBitmap = _nullBitmap == null ? null : (byte[])_nullBitmap.Clone();
  447. newBitmap._columnsCount = _columnsCount;
  448. return newBitmap;
  449. }
  450. internal void Clean() {
  451. _columnsCount = 0;
  452. // no need to free _nullBitmap array - it is cached for the next row
  453. }
  454. /// <summary>
  455. /// If this method returns true, the value is guaranteed to be null. This is not true vice versa:
  456. /// if the bitmat value is false (if this method returns false), the value can be either null or non-null - no guarantee in this case.
  457. /// To determine whether it is null or not, read it from the TDS (per NBCROW design spec, for IMAGE/TEXT/NTEXT columns server might send
  458. /// bitmap = 0, when the actual value is null).
  459. /// </summary>
  460. internal bool IsGuaranteedNull(int columnOrdinal) {
  461. if (_columnsCount == 0) {
  462. // not an NBC row
  463. return false;
  464. }
  465. Debug.Assert(columnOrdinal >= 0 && columnOrdinal < _columnsCount, "Invalid column ordinal");
  466. byte testBit = (byte)(1 << (columnOrdinal & 0x7)); // columnOrdinal & 0x7 == columnOrdinal MOD 0x7
  467. byte testByte = _nullBitmap[columnOrdinal >> 3];
  468. return (testBit & testByte) != 0;
  469. }
  470. }
  471. /////////////////////
  472. // General methods //
  473. /////////////////////
  474. // If this object is part of a TdsParserSessionPool, then this *must* be called inside the pool's lock
  475. internal void Activate(object owner) {
  476. Debug.Assert(_parser.MARSOn, "Can not activate a non-MARS connection");
  477. Owner = owner; // must assign an owner for reclaimation to work
  478. int result = Interlocked.Increment(ref _activateCount); // must have non-zero activation count for reclaimation to work too.
  479. Debug.Assert(result == 1, "invalid deactivate count");
  480. }
  481. // This method is only called by the command or datareader as a result of a user initiated
  482. // cancel request.
  483. internal void Cancel(int objectID) {
  484. bool hasLock = false;
  485. try {
  486. // Keep looping until we either grabbed the lock (and therefore sent attention) or the connection closes\breaks
  487. while ((!hasLock) && (_parser.State != TdsParserState.Closed) && (_parser.State != TdsParserState.Broken)) {
  488. Monitor.TryEnter(this, _waitForCancellationLockPollTimeout, ref hasLock);
  489. if (hasLock) { // Lock for the time being - since we need to synchronize the attention send.
  490. // At some point in the future, I hope to remove this.
  491. // This lock is also protecting against concurrent close and async continuations
  492. // don't allow objectID -1 since it is reserved for 'not associated with a command'
  493. // yes, the 2^32-1 comand won't cancel - but it also won't cancel when we don't want it
  494. if ((!_cancelled) && (objectID == _allowObjectID) && (objectID != -1)) {
  495. _cancelled = true;
  496. if (_pendingData && !_attentionSent) {
  497. bool hasParserLock = false;
  498. // Keep looping until we have the parser lock (and so are allowed to write), or the conneciton closes\breaks
  499. while ((!hasParserLock) && (_parser.State != TdsParserState.Closed) && (_parser.State != TdsParserState.Broken)) {
  500. try {
  501. _parser.Connection._parserLock.Wait(canReleaseFromAnyThread: false, timeout: _waitForCancellationLockPollTimeout, lockTaken: ref hasParserLock);
  502. if (hasParserLock) {
  503. _parser.Connection.ThreadHasParserLockForClose = true;
  504. SendAttention();
  505. }
  506. }
  507. finally {
  508. if (hasParserLock) {
  509. if (_parser.Connection.ThreadHasParserLockForClose) {
  510. _parser.Connection.ThreadHasParserLockForClose = false;
  511. }
  512. _parser.Connection._parserLock.Release();
  513. }
  514. }
  515. }
  516. }
  517. }
  518. }
  519. }
  520. }
  521. finally {
  522. if (hasLock) {
  523. Monitor.Exit(this);
  524. }
  525. }
  526. }
  527. // CancelRequest - use to cancel while writing a request to the server
  528. //
  529. // o none of the request might have been sent to the server, simply reset the buffer,
  530. // sending attention does not hurt
  531. // o the request was partially written. Send an ignore header to the server. attention is
  532. // required if the server was waiting for data (e.g. insert bulk rows)
  533. // o the request was completely written out and the server started to process the request.
  534. // attention is required to have the server stop processing.
  535. //
  536. internal void CancelRequest() {
  537. ResetBuffer(); // clear out unsent buffer
  538. // VSDD#903514, if the first sqlbulkcopy timeout, _outputPacketNumber may not be 1,
  539. // the next sqlbulkcopy (same connection string) requires this to be 1, hence reset
  540. // it here when exception happens in the first sqlbulkcopy
  541. _outputPacketNumber = 1;
  542. // VSDD#907507, if bulkcopy write timeout happens, it already sent the attention,
  543. // so no need to send it again
  544. if (!_bulkCopyWriteTimeout)
  545. {
  546. SendAttention();
  547. Parser.ProcessPendingAck(this);
  548. }
  549. }
  550. public void CheckSetResetConnectionState(UInt32 error, CallbackType callbackType) {
  551. // Should only be called for MARS - that is the only time we need to take
  552. // the ResetConnection lock!
  553. // SQL BU DT 333026 - it was raised in a security review by [....] questioning whether
  554. // we need to actually process the resulting packet (sp_reset ack or error) to know if the
  555. // reset actually succeeded. There was a concern that if the reset failed and we proceeded
  556. // there might be a security issue present. We have been assured by the server that if
  557. // sp_reset fails, they guarantee they will kill the resulting connection. So - it is
  558. // safe for us to simply receive the packet and then consume the pre-login later.
  559. Debug.Assert(_parser.MARSOn, "Should not be calling CheckSetResetConnectionState on non MARS connection");
  560. if (_fResetEventOwned) {
  561. if (callbackType == CallbackType.Read && TdsEnums.SNI_SUCCESS == error) {
  562. // RESET SUCCEEDED!
  563. // If we are on read callback and no error occurred (and we own reset event) -
  564. // then we sent the sp_reset_connection and so we need to reset sp_reset_connection
  565. // flag to false, and then release the ResetEvent.
  566. _parser._fResetConnection = false;
  567. _fResetConnectionSent = false;
  568. _fResetEventOwned = !_parser._resetConnectionEvent.Set();
  569. Debug.Assert(!_fResetEventOwned, "Invalid AutoResetEvent state!");
  570. }
  571. if (TdsEnums.SNI_SUCCESS != error) {
  572. // RESET FAILED!
  573. //
  574. // If write or read failed with reset, we need to clear event but not mark connection
  575. // as reset.
  576. _fResetConnectionSent = false;
  577. _fResetEventOwned = !_parser._resetConnectionEvent.Set();
  578. Debug.Assert(!_fResetEventOwned, "Invalid AutoResetEvent state!");
  579. }
  580. }
  581. }
  582. internal void CloseSession() {
  583. ResetCancelAndProcessAttention();
  584. #if DEBUG
  585. InvalidateDebugOnlyCopyOfSniContext();
  586. #endif
  587. Parser.PutSession(this);
  588. }
  589. private void ResetCancelAndProcessAttention() {
  590. // This method is shared by CloseSession initiated by DataReader.Close or completed
  591. // command execution, as well as the session reclaimation code for cases where the
  592. // DataReader is opened and then GC'ed.
  593. lock(this) {
  594. // Reset cancel state.
  595. _cancelled = false;
  596. _allowObjectID = -1;
  597. if (_attentionSent) {
  598. // Make sure we're cleaning up the AttentionAck if Cancel happened before taking the lock.
  599. // We serialize Cancel/CloseSession to prevent a race condition between these two states.
  600. // The problem is that both sending and receiving attentions are time taking
  601. // operations.
  602. #if DEBUG
  603. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  604. RuntimeHelpers.PrepareConstrainedRegions();
  605. try
  606. {
  607. tdsReliabilitySection.Start();
  608. #endif //DEBUG
  609. Parser.ProcessPendingAck(this);
  610. #if DEBUG
  611. }
  612. finally
  613. {
  614. tdsReliabilitySection.Stop();
  615. }
  616. #endif //DEBUG
  617. }
  618. _internalTimeout = false;
  619. }
  620. }
  621. private SNINativeMethodWrapper.ConsumerInfo CreateConsumerInfo(bool async) {
  622. SNINativeMethodWrapper.ConsumerInfo myInfo = new SNINativeMethodWrapper.ConsumerInfo();
  623. Debug.Assert(_outBuff.Length == _inBuff.Length, "Unexpected unequal buffers.");
  624. myInfo.defaultBufferSize = _outBuff.Length; // Obtain packet size from outBuff size.
  625. if (async) {
  626. myInfo.readDelegate = SNILoadHandle.SingletonInstance.ReadAsyncCallbackDispatcher;
  627. myInfo.writeDelegate = SNILoadHandle.SingletonInstance.WriteAsyncCallbackDispatcher;
  628. _gcHandle = GCHandle.Alloc(this, GCHandleType.Normal);
  629. myInfo.key = (IntPtr)_gcHandle;
  630. }
  631. return myInfo;
  632. }
  633. internal void CreatePhysicalSNIHandle(string serverName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, byte[] spnBuffer, bool flushCache, bool async, bool fParallel, TransparentNetworkResolutionState transparentNetworkResolutionState, int totalTimeout)
  634. {
  635. SNINativeMethodWrapper.ConsumerInfo myInfo = CreateConsumerInfo(async);
  636. // Translate to SNI timeout values (Int32 milliseconds)
  637. long timeout;
  638. if (Int64.MaxValue == timerExpire) {
  639. timeout = Int32.MaxValue;
  640. }
  641. else {
  642. timeout = ADP.TimerRemainingMilliseconds(timerExpire);
  643. if (timeout > Int32.MaxValue) {
  644. timeout = Int32.MaxValue;
  645. }
  646. else if (0 > timeout) {
  647. timeout = 0;
  648. }
  649. }
  650. _sessionHandle = new SNIHandle(myInfo, serverName, spnBuffer, ignoreSniOpenTimeout, checked((int)timeout), out instanceName, flushCache, !async, fParallel, transparentNetworkResolutionState, totalTimeout);
  651. }
  652. internal bool Deactivate() {
  653. bool goodForReuse = false;
  654. try {
  655. TdsParserState state = Parser.State;
  656. if (state != TdsParserState.Broken && state != TdsParserState.Closed) {
  657. if (_pendingData) {
  658. Parser.DrainData(this); // This may throw - taking us to catch block.
  659. }
  660. if (HasOpenResult) { // SQL BU DT 383773 - need to decrement openResultCount for all pending operations.
  661. DecrementOpenResultCount();
  662. }
  663. ResetCancelAndProcessAttention();
  664. goodForReuse = true;
  665. }
  666. }
  667. catch (Exception e) {
  668. if (!ADP.IsCatchableExceptionType(e)) {
  669. throw;
  670. }
  671. ADP.TraceExceptionWithoutRethrow(e);
  672. }
  673. return goodForReuse;
  674. }
  675. // If this object is part of a TdsParserSessionPool, then this *must* be called inside the pool's lock
  676. internal void RemoveOwner() {
  677. if (_parser.MARSOn) {
  678. // We only care about the activation count for MARS connections
  679. int result = Interlocked.Decrement(ref _activateCount); // must have non-zero activation count for reclaimation to work too.
  680. Debug.Assert(result == 0, "invalid deactivate count");
  681. }
  682. Owner = null;
  683. }
  684. internal void DecrementOpenResultCount() {
  685. if (_executedUnderTransaction == null) {
  686. // If we were not executed under a transaction - decrement the global count
  687. // on the parser.
  688. _parser.DecrementNonTransactedOpenResultCount();
  689. }
  690. else {
  691. // If we were executed under a transaction - decrement the count on the transaction.
  692. _executedUnderTransaction.DecrementAndObtainOpenResultCount();
  693. _executedUnderTransaction = null;
  694. }
  695. _hasOpenResult = false;
  696. }
  697. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  698. internal int DecrementPendingCallbacks(bool release) {
  699. int remaining = Interlocked.Decrement(ref _pendingCallbacks);
  700. if (Bid.AdvancedOn) {
  701. Bid.Trace("<sc.TdsParserStateObject.DecrementPendingCallbacks|ADV> %d#, after decrementing _pendingCallbacks: %d\n", ObjectID, _pendingCallbacks);
  702. }
  703. if ((0 == remaining || release) && _gcHandle.IsAllocated) {
  704. if (Bid.AdvancedOn) {
  705. Bid.Trace("<sc.TdsParserStateObject.DecrementPendingCallbacks|ADV> %d#, FREEING HANDLE!\n", ObjectID);
  706. }
  707. _gcHandle.Free();
  708. }
  709. // NOTE: TdsParserSessionPool may call DecrementPendingCallbacks on a TdsParserStateObject which is already disposed
  710. // This is not dangerous (since the stateObj is no longer in use), but we need to add a workaround in the assert for it
  711. Debug.Assert((remaining == -1 && _sessionHandle == null) || (0 <= remaining && remaining < 3), string.Format("_pendingCallbacks values is invalid after decrementing: {0}", remaining));
  712. return remaining;
  713. }
  714. internal void Dispose() {
  715. SafeHandle packetHandle = _sniPacket;
  716. SafeHandle sessionHandle = _sessionHandle;
  717. SafeHandle asyncAttnPacket = _sniAsyncAttnPacket;
  718. _sniPacket = null;
  719. _sessionHandle = null;
  720. _sniAsyncAttnPacket = null;
  721. Timer networkPacketTimeout = _networkPacketTimeout;
  722. if (networkPacketTimeout != null) {
  723. _networkPacketTimeout = null;
  724. networkPacketTimeout.Dispose();
  725. }
  726. Debug.Assert(Volatile.Read(ref _readingCount) >= 0, "_readingCount is negative");
  727. if (Volatile.Read(ref _readingCount) > 0) {
  728. // if _reading is true, we need to wait for it to complete
  729. // if _reading is false, then future read attempts will
  730. // already see the null _sessionHandle and abort.
  731. // We block after nulling _sessionHandle but before disposing it
  732. // to give a chance for a read that has already grabbed the
  733. // handle to complete.
  734. SpinWait.SpinUntil(() => Volatile.Read(ref _readingCount) == 0);
  735. }
  736. if (null != sessionHandle || null != packetHandle) {
  737. // Comment CloseMARSSession
  738. //
  739. //
  740. RuntimeHelpers.PrepareConstrainedRegions();
  741. try {} finally {
  742. if (packetHandle != null) {
  743. packetHandle.Dispose();
  744. }
  745. if (asyncAttnPacket != null) {
  746. asyncAttnPacket.Dispose ();
  747. }
  748. if (sessionHandle != null) {
  749. sessionHandle.Dispose();
  750. DecrementPendingCallbacks(true); // Will dispose of GC handle.
  751. }
  752. }
  753. }
  754. if (_writePacketCache != null) {
  755. lock (_writePacketLockObject) {
  756. RuntimeHelpers.PrepareConstrainedRegions();
  757. try {} finally {
  758. _writePacketCache.Dispose();
  759. // Do not set _writePacketCache to null, just in case a WriteAsyncCallback completes after this point
  760. }
  761. }
  762. }
  763. }
  764. internal Int32 IncrementAndObtainOpenResultCount(SqlInternalTransaction transaction) {
  765. _hasOpenResult = true;
  766. if (transaction == null) {
  767. // If we are not passed a transaction, we are not executing under a transaction
  768. // and thus we should increment the global connection result count.
  769. return _parser.IncrementNonTransactedOpenResultCount();
  770. }
  771. else {
  772. // If we are passed a transaction, we are executing under a transaction
  773. // and thus we should increment the transaction's result count.
  774. _executedUnderTransaction = transaction;
  775. return transaction.IncrementAndObtainOpenResultCount();
  776. }
  777. }
  778. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  779. internal int IncrementPendingCallbacks() {
  780. int remaining = Interlocked.Increment(ref _pendingCallbacks);
  781. if (Bid.AdvancedOn) {
  782. Bid.Trace("<sc.TdsParserStateObject.IncrementPendingCallbacks|ADV> %d#, after incrementing _pendingCallbacks: %d\n", ObjectID, _pendingCallbacks);
  783. }
  784. Debug.Assert(0 < remaining && remaining <= 3, string.Format("_pendingCallbacks values is invalid after incrementing: {0}", remaining));
  785. return remaining;
  786. }
  787. internal void SetTimeoutSeconds(int timeout) {
  788. SetTimeoutMilliseconds((long)timeout * 1000L);
  789. }
  790. internal void SetTimeoutMilliseconds(long timeout) {
  791. if (timeout <= 0) {
  792. // 0 or less (i.e. Timespan.Infinite) == infinite (which is represented by Int64.MaxValue)
  793. _timeoutMilliseconds = 0;
  794. _timeoutTime = Int64.MaxValue;
  795. }
  796. else {
  797. _timeoutMilliseconds = timeout;
  798. _timeoutTime = 0;
  799. }
  800. }
  801. internal void StartSession(int objectID) {
  802. _allowObjectID = objectID;
  803. }
  804. internal void ThrowExceptionAndWarning(bool callerHasConnectionLock = false, bool asyncClose = false) {
  805. _parser.ThrowExceptionAndWarning(this, callerHasConnectionLock, asyncClose);
  806. }
  807. ////////////////////////////////////////////
  808. // TDS Packet/buffer manipulation methods //
  809. ////////////////////////////////////////////
  810. internal Task ExecuteFlush() {
  811. lock (this) {
  812. if (_cancelled && 1 == _outputPacketNumber) {
  813. ResetBuffer();
  814. _cancelled = false;
  815. throw SQL.OperationCancelled();
  816. }
  817. else {
  818. Task writePacketTask = WritePacket(TdsEnums.HARDFLUSH);
  819. if (writePacketTask == null) {
  820. _pendingData = true;
  821. _messageStatus = 0;
  822. return null;
  823. }
  824. else {
  825. return AsyncHelper.CreateContinuationTask(writePacketTask, () => { _pendingData = true; _messageStatus = 0; });
  826. }
  827. }
  828. }
  829. }
  830. // Processes the tds header that is present in the buffer
  831. internal bool TryProcessHeader() {
  832. Debug.Assert(_inBytesPacket == 0, "there should not be any bytes left in packet when ReadHeader is called");
  833. // if the header splits buffer reads - special case!
  834. if ((_partialHeaderBytesRead > 0) || (_inBytesUsed + _inputHeaderLen > _inBytesRead)) {
  835. // VSTS 219884: when some kind of MITM (man-in-the-middle) tool splits the network packets, the message header can be split over
  836. // several network packets.
  837. // Note: cannot use ReadByteArray here since it uses _inBytesPacket which is not set yet.
  838. do {
  839. int copy = Math.Min(_inBytesRead - _inBytesUsed, _inputHeaderLen - _partialHeaderBytesRead);
  840. Debug.Assert(copy > 0, "ReadNetworkPacket read empty buffer");
  841. Buffer.BlockCopy(_inBuff, _inBytesUsed, _partialHeaderBuffer, _partialHeaderBytesRead, copy);
  842. _partialHeaderBytesRead += copy;
  843. _inBytesUsed += copy;
  844. Debug.Assert(_partialHeaderBytesRead <= _inputHeaderLen, "Read more bytes for header than required");
  845. if (_partialHeaderBytesRead == _inputHeaderLen) {
  846. // All read
  847. _partialHeaderBytesRead = 0;
  848. _inBytesPacket = ((int)_partialHeaderBuffer[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8 |
  849. (int)_partialHeaderBuffer[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - _inputHeaderLen;
  850. _messageStatus = _partialHeaderBuffer[1];
  851. }
  852. else {
  853. Debug.Assert(_inBytesUsed == _inBytesRead, "Did not use all data while reading partial header");
  854. // Require more data
  855. if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
  856. // NOTE: ReadNetworkPacket does nothing if the parser state is closed or broken
  857. // to avoid infinite loop, we raise an exception
  858. ThrowExceptionAndWarning();
  859. //
  860. return true;
  861. }
  862. if (!TryReadNetworkPacket()) {
  863. return false;
  864. }
  865. if (_internalTimeout) {
  866. ThrowExceptionAndWarning();
  867. //
  868. return true;
  869. }
  870. }
  871. } while (_partialHeaderBytesRead != 0); // This is reset to 0 once we have read everything that we need
  872. AssertValidState();
  873. }
  874. else {
  875. // normal header processing...
  876. _messageStatus = _inBuff[_inBytesUsed + 1];
  877. _inBytesPacket = ((int)_inBuff[_inBytesUsed + TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8 |
  878. (int)_inBuff[_inBytesUsed + TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - _inputHeaderLen;
  879. _inBytesUsed += _inputHeaderLen;
  880. AssertValidState();
  881. }
  882. if (_inBytesPacket < 0) {
  883. // either TDS stream is corrupted or there is multithreaded misuse of connection
  884. // NOTE: usually we do not proactively apply checks to TDS data, but this situation happened several times
  885. // and caused infinite loop in CleanWire (VSTFDEVDIV\DEVDIV2:149937)
  886. throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream);
  887. }
  888. return true;
  889. }
  890. // This ensure that there is data available to be read in the buffer and that the header has been processed
  891. // NOTE: This method (and all it calls) should be retryable without replaying a snapshot
  892. internal bool TryPrepareBuffer() {
  893. TdsParser.ReliabilitySection.Assert("unreliable call to ReadBuffer"); // you need to setup for a thread abort somewhere before you call this method
  894. Debug.Assert(_inBuff != null, "packet buffer should not be null!");
  895. // Header spans packets, or we haven't read the header yet - process header
  896. if ((_inBytesPacket == 0) && (_inBytesUsed < _inBytesRead)) {
  897. if (!TryProcessHeader()) {
  898. return false;
  899. }
  900. Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!");
  901. AssertValidState();
  902. }
  903. // If we're out of data, need to read more
  904. if (_inBytesUsed == _inBytesRead) {
  905. // If the _inBytesPacket is not zero, then we have data left in the packet, but the data in the packet
  906. // spans the buffer, so we can read any amount of data possible, and we do not need to call ProcessHeader
  907. // because there isn't a header at the beginning of the data that we are reading.
  908. if (_inBytesPacket > 0) {
  909. if (!TryReadNetworkPacket()) {
  910. return false;
  911. }
  912. }
  913. else if (_inBytesPacket == 0) {
  914. // Else we have finished the packet and so we must read as much data as possible
  915. if (!TryReadNetworkPacket()) {
  916. return false;
  917. }
  918. if (!TryProcessHeader()) {
  919. return false;
  920. }
  921. Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!");
  922. if (_inBytesUsed == _inBytesRead) {
  923. // we read a header but didn't get anything else except it
  924. // VSTS 219884: it can happen that the TDS packet header and its data are split across two network packets.
  925. // Read at least one more byte to get/cache the first data portion of this TDS packet
  926. if (!TryReadNetworkPacket()) {
  927. return false;
  928. }
  929. }
  930. }
  931. else {
  932. Debug.Assert(false, "entered negative _inBytesPacket loop");
  933. }
  934. AssertValidState();
  935. }
  936. return true;
  937. }
  938. internal void ResetBuffer() {
  939. _outBytesUsed = _outputHeaderLen;
  940. }
  941. internal bool SetPacketSize(int size) {
  942. if (size > TdsEnums.MAX_PACKET_SIZE) {
  943. throw SQL.InvalidPacketSize();
  944. }
  945. Debug.Assert(size >= 1, "Cannot set packet size to less than 1.");
  946. Debug.Assert( (_outBuff == null && _inBuff == null) ||
  947. (_outBuff.Length == _inBuff.Length),
  948. "Buffers are not in consistent state");
  949. Debug.Assert( (_outBuff == null && _inBuff == null) ||
  950. this == _parser._physicalStateObj,
  951. "SetPacketSize should only be called on a stateObj with null buffers on the physicalStateObj!");
  952. Debug.Assert( _inBuff == null
  953. ||
  954. (_parser.IsYukonOrNewer &&
  955. _outBytesUsed == (_outputHeaderLen + BitConverter.ToInt32(_outBuff, _outputHeaderLen)) &&
  956. _outputPacketNumber == 1)
  957. ||
  958. (_outBytesUsed == _outputHeaderLen && _outputPacketNumber == 1),
  959. "SetPacketSize called with data in the buffer!");
  960. if (_inBuff == null || _inBuff.Length != size) { // We only check _inBuff, since two buffers should be consistent.
  961. // Allocate or re-allocate _inBuff.
  962. if (_inBuff == null) {
  963. _inBuff = new byte[size];
  964. _inBytesRead = 0;
  965. _inBytesUsed = 0;
  966. }
  967. else if (size != _inBuff.Length) {
  968. // If new size is other than existing...
  969. if (_inBytesRead > _inBytesUsed) {
  970. // if we still have data left in the buffer we must keep that array reference and then copy into new one
  971. byte[] temp = _inBuff;
  972. _inBuff = new byte[size];
  973. // copy remainder of unused data
  974. int remainingData = _inBytesRead - _inBytesUsed;
  975. if ((temp.Length < _inBytesUsed + remainingData) || (_inBuff.Length < remainingData)) {
  976. string errormessage = Res.GetString(Res.SQL_InvalidInternalPacketSize) + ' ' + temp.Length + ", " + _inBytesUsed + ", " + remainingData + ", " + _inBuff.Length;
  977. throw SQL.InvalidInternalPacketSize (errormessage);
  978. }
  979. Buffer.BlockCopy(temp, _inBytesUsed, _inBuff, 0, remainingData);
  980. _inBytesRead = _inBytesRead - _inBytesUsed;
  981. _inBytesUsed = 0;
  982. AssertValidState();
  983. }
  984. else {
  985. // buffer is empty - just create the new one that is double the size of the old one
  986. _inBuff = new byte[size];
  987. _inBytesRead = 0;
  988. _inBytesUsed = 0;
  989. }
  990. }
  991. // Always re-allocate _outBuff - assert is above to verify state.
  992. _outBuff = new byte[size];
  993. _outBytesUsed = _outputHeaderLen;
  994. AssertValidState();
  995. return true;
  996. }
  997. return false;
  998. }
  999. ///////////////////////////////////////
  1000. // Buffer read methods - data values //
  1001. ///////////////////////////////////////
  1002. // look at the next byte without pulling it off the wire, don't just returun _inBytesUsed since we may
  1003. // have to go to the network to get the next byte.
  1004. internal bool TryPeekByte(out byte value) {
  1005. if (!TryReadByte(out value)) {
  1006. return false;
  1007. }
  1008. // now do fixup
  1009. _inBytesPacket++;
  1010. _inBytesUsed--;
  1011. AssertValidState();
  1012. return true;
  1013. }
  1014. // Takes a byte array, an offset, and a len and fills the array from the offset to len number of
  1015. // bytes from the in buffer.
  1016. public bool TryReadByteArray(byte[] buff, int offset, int len) {
  1017. int ignored;
  1018. return TryReadByteArray(buff, offset, len, out ignored);
  1019. }
  1020. // NOTE: This method must be retriable WITHOUT replaying a snapshot
  1021. // Every time you call this method increment the offset and decrease len by the value of totalRead
  1022. public bool TryReadByteArray(byte[] buff, int offset, int len, out int totalRead) {
  1023. TdsParser.ReliabilitySection.Assert("unreliable call to ReadByteArray"); // you need to setup for a thread abort somewhere before you call this method
  1024. totalRead = 0;
  1025. #if DEBUG
  1026. if (_snapshot != null && _snapshot.DoPend()) {
  1027. _networkPacketTaskSource = new TaskCompletionSource<object>();
  1028. Thread.MemoryBarrier();
  1029. if (_forcePendingReadsToWaitForUser) {
  1030. _realNetworkPacketTaskSource = new TaskCompletionSource<object>();
  1031. _realNetworkPacketTaskSource.SetResult(null);
  1032. }
  1033. else {
  1034. _networkPacketTaskSource.TrySetResult(null);
  1035. }
  1036. return false;
  1037. }
  1038. #endif
  1039. Debug.Assert(buff == null || buff.Length >= len, "Invalid length sent to ReadByteArray()!");
  1040. // loop through and read up to array length
  1041. while (len > 0) {
  1042. if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead)) {
  1043. if (!TryPrepareBuffer()) {
  1044. return false;
  1045. }
  1046. }
  1047. int bytesToRead = Math.Min(len, Math.Min(_inBytesPacket, _inBytesRead - _inBytesUsed));
  1048. Debug.Assert(bytesToRead > 0, "0 byte read in TryReadByteArray");
  1049. if (buff != null) {
  1050. Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset + totalRead, bytesToRead);
  1051. }
  1052. totalRead += bytesToRead;
  1053. _inBytesUsed += bytesToRead;
  1054. _inBytesPacket -= bytesToRead;
  1055. len -= bytesToRead;
  1056. AssertValidState();
  1057. }
  1058. if ((_messageStatus != TdsEnums.ST_EOM) && ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead))) {
  1059. if (!TryPrepareBuffer()) {
  1060. return false;
  1061. }
  1062. }
  1063. AssertValidState();
  1064. return true;
  1065. }
  1066. // Takes no arguments and returns a byte from the buffer. If the buffer is empty, it is filled
  1067. // before the byte is returned.
  1068. internal bool TryReadByte(out byte value) {
  1069. TdsParser.ReliabilitySection.Assert("unreliable call to ReadByte"); // you need to setup for a thread abort somewhere before you call this method
  1070. Debug.Assert(_inBytesUsed >= 0 && _inBytesUsed <= _inBytesRead, "ERROR - TDSParser: _inBytesUsed < 0 or _inBytesUsed > _inBytesRead");
  1071. value = 0;
  1072. #if DEBUG
  1073. if (_snapshot != null && _snapshot.DoPend()) {
  1074. _networkPacketTaskSource = new TaskCompletionSource<object>();
  1075. Thread.MemoryBarrier();
  1076. if (_forcePendingReadsToWaitForUser) {
  1077. _realNetworkPacketTaskSource = new TaskCompletionSource<object>();
  1078. _realNetworkPacketTaskSource.SetResult(null);
  1079. }
  1080. else {
  1081. _networkPacketTaskSource.TrySetResult(null);
  1082. }
  1083. return false;
  1084. }
  1085. #endif
  1086. if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead)) {
  1087. if (!TryPrepareBuffer()) {
  1088. return false;
  1089. }
  1090. }
  1091. // decrement the number of bytes left in the packet
  1092. _inBytesPacket--;
  1093. Debug.Assert(_inBytesPacket >= 0, "ERROR - TDSParser: _inBytesPacket < 0");
  1094. // return the byte from the buffer and increment the counter for number of bytes used in the in buffer
  1095. value = (_inBuff[_inBytesUsed++]);
  1096. AssertValidState();
  1097. return true;
  1098. }
  1099. internal bool TryReadChar(out char value) {
  1100. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1101. byte[] buffer;
  1102. int offset;
  1103. if (((_inBytesUsed + 2) > _inBytesRead) || (_inBytesPacket < 2)) {
  1104. // If the char isn't fully in the buffer, or if it isn't fully in the packet,
  1105. // then use ReadByteArray since the logic is there to take care of that.
  1106. if (!TryReadByteArray(_bTmp, 0, 2)) {
  1107. value = '\0';
  1108. return false;
  1109. }
  1110. buffer = _bTmp;
  1111. offset = 0;
  1112. }
  1113. else {
  1114. // The entire char is in the packet and in the buffer, so just return it
  1115. // and take care of the counters.
  1116. buffer = _inBuff;
  1117. offset = _inBytesUsed;
  1118. _inBytesUsed += 2;
  1119. _inBytesPacket -= 2;
  1120. }
  1121. AssertValidState();
  1122. value = (char)((buffer[offset + 1] << 8) + buffer[offset]);
  1123. return true;
  1124. }
  1125. internal bool TryReadInt16(out short value) {
  1126. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1127. byte[] buffer;
  1128. int offset;
  1129. if (((_inBytesUsed + 2) > _inBytesRead) || (_inBytesPacket < 2)) {
  1130. // If the int16 isn't fully in the buffer, or if it isn't fully in the packet,
  1131. // then use ReadByteArray since the logic is there to take care of that.
  1132. if (!TryReadByteArray(_bTmp, 0, 2)) {
  1133. value = default(short);
  1134. return false;
  1135. }
  1136. buffer = _bTmp;
  1137. offset = 0;
  1138. }
  1139. else {
  1140. // The entire int16 is in the packet and in the buffer, so just return it
  1141. // and take care of the counters.
  1142. buffer = _inBuff;
  1143. offset = _inBytesUsed;
  1144. _inBytesUsed += 2;
  1145. _inBytesPacket -= 2;
  1146. }
  1147. AssertValidState();
  1148. value = (Int16)((buffer[offset + 1] << 8) + buffer[offset]);
  1149. return true;
  1150. }
  1151. internal bool TryReadInt32(out int value) {
  1152. TdsParser.ReliabilitySection.Assert("unreliable call to ReadInt32"); // you need to setup for a thread abort somewhere before you call this method
  1153. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1154. if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) {
  1155. // If the int isn't fully in the buffer, or if it isn't fully in the packet,
  1156. // then use ReadByteArray since the logic is there to take care of that.
  1157. if (!TryReadByteArray(_bTmp, 0, 4)) {
  1158. value = 0;
  1159. return false;
  1160. }
  1161. AssertValidState();
  1162. value = BitConverter.ToInt32(_bTmp, 0);
  1163. return true;
  1164. }
  1165. else {
  1166. // The entire int is in the packet and in the buffer, so just return it
  1167. // and take care of the counters.
  1168. value = BitConverter.ToInt32(_inBuff, _inBytesUsed);
  1169. _inBytesUsed += 4;
  1170. _inBytesPacket -= 4;
  1171. AssertValidState();
  1172. return true;
  1173. }
  1174. }
  1175. // This method is safe to call when doing async without snapshot
  1176. internal bool TryReadInt64(out long value) {
  1177. TdsParser.ReliabilitySection.Assert("unreliable call to ReadInt64"); // you need to setup for a thread abort somewhere before you call this method
  1178. if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead)) {
  1179. if (!TryPrepareBuffer()) {
  1180. value = 0;
  1181. return false;
  1182. }
  1183. }
  1184. if ((_bTmpRead > 0) || (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8))) {
  1185. // If the long isn't fully in the buffer, or if it isn't fully in the packet,
  1186. // then use ReadByteArray since the logic is there to take care of that.
  1187. int bytesRead = 0;
  1188. if (!TryReadByteArray(_bTmp, _bTmpRead, 8 - _bTmpRead, out bytesRead)) {
  1189. Debug.Assert(_bTmpRead + bytesRead <= 8, "Read more data than required");
  1190. _bTmpRead += bytesRead;
  1191. value = 0;
  1192. return false;
  1193. }
  1194. else {
  1195. Debug.Assert(_bTmpRead + bytesRead == 8, "TryReadByteArray returned true without reading all data required");
  1196. _bTmpRead = 0;
  1197. AssertValidState();
  1198. value = BitConverter.ToInt64(_bTmp, 0);
  1199. return true;
  1200. }
  1201. }
  1202. else {
  1203. // The entire long is in the packet and in the buffer, so just return it
  1204. // and take care of the counters.
  1205. value = BitConverter.ToInt64(_inBuff, _inBytesUsed);
  1206. _inBytesUsed += 8;
  1207. _inBytesPacket -= 8;
  1208. AssertValidState();
  1209. return true;
  1210. }
  1211. }
  1212. internal bool TryReadUInt16(out ushort value) {
  1213. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1214. byte[] buffer;
  1215. int offset;
  1216. if (((_inBytesUsed + 2) > _inBytesRead) || (_inBytesPacket < 2)) {
  1217. // If the uint16 isn't fully in the buffer, or if it isn't fully in the packet,
  1218. // then use ReadByteArray since the logic is there to take care of that.
  1219. if (!TryReadByteArray(_bTmp, 0, 2)) {
  1220. value = default(ushort);
  1221. return false;
  1222. }
  1223. buffer = _bTmp;
  1224. offset = 0;
  1225. }
  1226. else {
  1227. // The entire uint16 is in the packet and in the buffer, so just return it
  1228. // and take care of the counters.
  1229. buffer = _inBuff;
  1230. offset = _inBytesUsed;
  1231. _inBytesUsed += 2;
  1232. _inBytesPacket -= 2;
  1233. }
  1234. AssertValidState();
  1235. value = (UInt16)((buffer[offset + 1] << 8) + buffer[offset]);
  1236. return true;
  1237. }
  1238. // This method is safe to call when doing async without replay
  1239. internal bool TryReadUInt32(out uint value) {
  1240. TdsParser.ReliabilitySection.Assert("unreliable call to ReadUInt32"); // you need to setup for a thread abort somewhere before you call this method
  1241. if ((_inBytesPacket == 0) || (_inBytesUsed == _inBytesRead)) {
  1242. if (!TryPrepareBuffer()) {
  1243. value = 0;
  1244. return false;
  1245. }
  1246. }
  1247. if ((_bTmpRead > 0) || (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4))) {
  1248. // If the int isn't fully in the buffer, or if it isn't fully in the packet,
  1249. // then use ReadByteArray since the logic is there to take care of that.
  1250. int bytesRead = 0;
  1251. if (!TryReadByteArray(_bTmp, _bTmpRead, 4 - _bTmpRead, out bytesRead)) {
  1252. Debug.Assert(_bTmpRead + bytesRead <= 4, "Read more data than required");
  1253. _bTmpRead += bytesRead;
  1254. value = 0;
  1255. return false;
  1256. }
  1257. else {
  1258. Debug.Assert(_bTmpRead + bytesRead == 4, "TryReadByteArray returned true without reading all data required");
  1259. _bTmpRead = 0;
  1260. AssertValidState();
  1261. value = BitConverter.ToUInt32(_bTmp, 0);
  1262. return true;
  1263. }
  1264. }
  1265. else {
  1266. // The entire int is in the packet and in the buffer, so just return it
  1267. // and take care of the counters.
  1268. value = BitConverter.ToUInt32(_inBuff, _inBytesUsed);
  1269. _inBytesUsed += 4;
  1270. _inBytesPacket -= 4;
  1271. AssertValidState();
  1272. return true;
  1273. }
  1274. }
  1275. internal bool TryReadSingle(out float value) {
  1276. TdsParser.ReliabilitySection.Assert("unreliable call to ReadSingle"); // you need to setup for a thread abort somewhere before you call this method
  1277. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1278. if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) {
  1279. // If the float isn't fully in the buffer, or if it isn't fully in the packet,
  1280. // then use ReadByteArray since the logic is there to take care of that.
  1281. if (!TryReadByteArray(_bTmp, 0, 4)) {
  1282. value = default(float);
  1283. return false;
  1284. }
  1285. AssertValidState();
  1286. value = BitConverter.ToSingle(_bTmp, 0);
  1287. return true;
  1288. }
  1289. else {
  1290. // The entire float is in the packet and in the buffer, so just return it
  1291. // and take care of the counters.
  1292. value = BitConverter.ToSingle(_inBuff, _inBytesUsed);
  1293. _inBytesUsed += 4;
  1294. _inBytesPacket -= 4;
  1295. AssertValidState();
  1296. return true;
  1297. }
  1298. }
  1299. internal bool TryReadDouble(out double value) {
  1300. TdsParser.ReliabilitySection.Assert("unreliable call to ReadDouble"); // you need to setup for a thread abort somewhere before you call this method
  1301. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1302. if (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8)) {
  1303. // If the double isn't fully in the buffer, or if it isn't fully in the packet,
  1304. // then use ReadByteArray since the logic is there to take care of that.
  1305. if (!TryReadByteArray(_bTmp, 0, 8)) {
  1306. value = default(double);
  1307. return false;
  1308. }
  1309. AssertValidState();
  1310. value = BitConverter.ToDouble(_bTmp, 0);
  1311. return true;
  1312. }
  1313. else {
  1314. // The entire double is in the packet and in the buffer, so just return it
  1315. // and take care of the counters.
  1316. value = BitConverter.ToDouble(_inBuff, _inBytesUsed);
  1317. _inBytesUsed += 8;
  1318. _inBytesPacket -= 8;
  1319. AssertValidState();
  1320. return true;
  1321. }
  1322. }
  1323. internal bool TryReadString(int length, out string value) {
  1324. TdsParser.ReliabilitySection.Assert("unreliable call to ReadString"); // you need to setup for a thread abort somewhere before you call this method
  1325. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1326. int cBytes = length << 1;
  1327. byte[] buf;
  1328. int offset = 0;
  1329. if (((_inBytesUsed + cBytes) > _inBytesRead) || (_inBytesPacket < cBytes)) {
  1330. if (_bTmp == null || _bTmp.Length < cBytes) {
  1331. _bTmp = new byte[cBytes];
  1332. }
  1333. if (!TryReadByteArray(_bTmp, 0, cBytes)) {
  1334. value = null;
  1335. return false;
  1336. }
  1337. // assign local to point to parser scratch buffer
  1338. buf = _bTmp;
  1339. AssertValidState();
  1340. }
  1341. else {
  1342. // assign local to point to _inBuff
  1343. buf = _inBuff;
  1344. offset = _inBytesUsed;
  1345. _inBytesUsed += cBytes;
  1346. _inBytesPacket -= cBytes;
  1347. AssertValidState();
  1348. }
  1349. value = System.Text.Encoding.Unicode.GetString(buf, offset, cBytes);
  1350. return true;
  1351. }
  1352. internal bool TryReadStringWithEncoding(int length, System.Text.Encoding encoding, bool isPlp, out string value) {
  1353. TdsParser.ReliabilitySection.Assert("unreliable call to ReadStringWithEncoding"); // you need to setup for a thread abort somewhere before you call this method
  1354. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1355. if (null == encoding) {
  1356. // Bug 462435:CR: TdsParser.DrainData(stateObj) hitting timeout exception after Connection Resiliency change
  1357. // http://vstfdevdiv:8080/web/wi.aspx?pcguid=22f9acc9-569a-41ff-b6ac-fac1b6370209&id=462435
  1358. // Need to skip the current column before throwing the error - this ensures that the state shared between this and the data reader is consistent when calling DrainData
  1359. if (isPlp) {
  1360. ulong ignored;
  1361. if (!_parser.TrySkipPlpValue((ulong)length, this, out ignored)) {
  1362. value = null;
  1363. return false;
  1364. }
  1365. }
  1366. else {
  1367. if (!TrySkipBytes(length)) {
  1368. value = null;
  1369. return false;
  1370. }
  1371. }
  1372. _parser.ThrowUnsupportedCollationEncountered(this);
  1373. }
  1374. byte[] buf = null;
  1375. int offset = 0;
  1376. if (isPlp) {
  1377. if (!TryReadPlpBytes(ref buf, 0, Int32.MaxValue, out length)) {
  1378. value = null;
  1379. return false;
  1380. }
  1381. AssertValidState();
  1382. }
  1383. else {
  1384. if (((_inBytesUsed + length) > _inBytesRead) || (_inBytesPacket < length)) {
  1385. if (_bTmp == null || _bTmp.Length < length) {
  1386. _bTmp = new byte[length];
  1387. }
  1388. if (!TryReadByteArray(_bTmp, 0, length)) {
  1389. value = null;
  1390. return false;
  1391. }
  1392. // assign local to point to parser scratch buffer
  1393. buf = _bTmp;
  1394. AssertValidState();
  1395. }
  1396. else {
  1397. // assign local to point to _inBuff
  1398. buf = _inBuff;
  1399. offset = _inBytesUsed;
  1400. _inBytesUsed += length;
  1401. _inBytesPacket -= length;
  1402. AssertValidState();
  1403. }
  1404. }
  1405. // BCL optimizes to not use char[] underneath
  1406. value = encoding.GetString(buf, offset, length);
  1407. return true;
  1408. }
  1409. internal ulong ReadPlpLength(bool returnPlpNullIfNull) {
  1410. ulong value;
  1411. Debug.Assert(_syncOverAsync, "Should not attempt pends in a synchronous call");
  1412. bool result = TryReadPlpLength(returnPlpNullIfNull, out value);
  1413. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  1414. return value;
  1415. }
  1416. // Reads the length of either the entire data or the length of the next chunk in a
  1417. // partially length prefixed data
  1418. // After this call, call ReadPlpBytes/ReadPlpUnicodeChars untill the specified length of data
  1419. // is consumed. Repeat this until ReadPlpLength returns 0 in order to read the
  1420. // entire stream.
  1421. // When this function returns 0, it means the data stream is read completely and the
  1422. // plp state in the tdsparser is cleaned.
  1423. internal bool TryReadPlpLength(bool returnPlpNullIfNull, out ulong lengthLeft) {
  1424. uint chunklen;
  1425. // bool firstchunk = false;
  1426. bool isNull = false;
  1427. Debug.Assert(_longlenleft == 0, "Out of synch length read request");
  1428. if (_longlen == 0) {
  1429. // First chunk is being read. Find out what type of chunk it is
  1430. long value;
  1431. if (!TryReadInt64(out value)) {
  1432. lengthLeft = 0;
  1433. return false;
  1434. }
  1435. _longlen = (ulong)value;
  1436. // firstchunk = true;
  1437. }
  1438. if (_longlen == TdsEnums.SQL_PLP_NULL) {
  1439. _longlen = 0;
  1440. _longlenleft = 0;
  1441. isNull = true;
  1442. }
  1443. else {
  1444. // Data is coming in uint chunks, read length of next chunk
  1445. if (!TryReadUInt32(out chunklen)) {
  1446. lengthLeft = 0;
  1447. return false;
  1448. }
  1449. if (chunklen == TdsEnums.SQL_PLP_CHUNK_TERMINATOR) {
  1450. _longlenleft = 0;
  1451. _longlen = 0;
  1452. }
  1453. else {
  1454. _longlenleft = (ulong)chunklen;
  1455. }
  1456. }
  1457. AssertValidState();
  1458. if (isNull && returnPlpNullIfNull) {
  1459. lengthLeft = TdsEnums.SQL_PLP_NULL;
  1460. return true;
  1461. }
  1462. lengthLeft = _longlenleft;
  1463. return true;
  1464. }
  1465. internal int ReadPlpBytesChunk(byte[] buff, int offset, int len) {
  1466. Debug.Assert(_syncOverAsync, "Should not attempt pends in a synchronous call");
  1467. Debug.Assert(_longlenleft > 0, "Read when no data available");
  1468. int value;
  1469. int bytesToRead = (int)Math.Min(_longlenleft, (ulong)len);
  1470. bool result = TryReadByteArray(buff, offset, bytesToRead, out value);
  1471. _longlenleft -= (ulong)bytesToRead;
  1472. if (!result) { throw SQL.SynchronousCallMayNotPend(); }
  1473. return value;
  1474. }
  1475. // Reads the requested number of bytes from a plp data stream, or the entire data if
  1476. // requested length is -1 or larger than the actual length of data. First call to this method
  1477. // should be preceeded by a call to ReadPlpLength or ReadDataLength.
  1478. // Returns the actual bytes read.
  1479. // NOTE: This method must be retriable WITHOUT replaying a snapshot
  1480. // Every time you call this method increment the offst and decrease len by the value of totalBytesRead
  1481. internal bool TryReadPlpBytes(ref byte[] buff, int offst, int len, out int totalBytesRead) {
  1482. int bytesRead = 0;
  1483. int bytesLeft;
  1484. byte[] newbuf;
  1485. ulong ignored;
  1486. if (_longlen == 0) {
  1487. Debug.Assert(_longlenleft == 0);
  1488. if (buff == null) {
  1489. buff = new byte[0];
  1490. }
  1491. AssertValidState();
  1492. totalBytesRead = 0;
  1493. return true; // No data
  1494. }
  1495. Debug.Assert((_longlen != TdsEnums.SQL_PLP_NULL),
  1496. "Out of sync plp read request");
  1497. Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpBytes()!");
  1498. bytesLeft = len;
  1499. // If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time
  1500. if (buff == null && _longlen != TdsEnums.SQL_PLP_UNKNOWNLEN) {
  1501. buff = new byte[(int)Math.Min((int)_longlen, len)];
  1502. }
  1503. if (_longlenleft == 0) {
  1504. if (!TryReadPlpLength(false, out ignored)) {
  1505. totalBytesRead = 0;
  1506. return false;
  1507. }
  1508. if (_longlenleft == 0) { // Data read complete
  1509. totalBytesRead = 0;
  1510. return true;
  1511. }
  1512. }
  1513. if (buff == null) {
  1514. buff = new byte[_longlenleft];
  1515. }
  1516. totalBytesRead = 0;
  1517. while (bytesLeft > 0) {
  1518. int bytesToRead = (int)Math.Min(_longlenleft, (ulong)bytesLeft);
  1519. if (buff.Length < (offst + bytesToRead)) {
  1520. // Grow the array
  1521. newbuf = new byte[offst + bytesToRead];
  1522. Buffer.BlockCopy(buff, 0, newbuf, 0, offst);
  1523. buff = newbuf;
  1524. }
  1525. bool result = TryReadByteArray(buff, offst, bytesToRead, out bytesRead);
  1526. Debug.Assert(bytesRead <= bytesLeft, "Read more bytes than we needed");
  1527. Debug.Assert((ulong)bytesRead <= _longlenleft, "Read more bytes than is available");
  1528. bytesLeft -= bytesRead;
  1529. offst += bytesRead;
  1530. totalBytesRead += bytesRead;
  1531. _longlenleft -= (ulong)bytesRead;
  1532. if (!result) {
  1533. return false;
  1534. }
  1535. if (_longlenleft == 0) { // Read the next chunk or cleanup state if hit the end
  1536. if (!TryReadPlpLength(false, out ignored)) {
  1537. return false;
  1538. }
  1539. }
  1540. AssertValidState();
  1541. // Catch the point where we read the entire plp data stream and clean up state
  1542. if (_longlenleft == 0) // Data read complete
  1543. break;
  1544. }
  1545. return true;
  1546. }
  1547. /////////////////////////////////////////
  1548. // Value Skip Logic //
  1549. /////////////////////////////////////////
  1550. // Reads bytes from the buffer but doesn't return them, in effect simply deleting them.
  1551. // Does not handle plp fields, need to use SkipPlpBytesValue for those.
  1552. // Does not handle null values or NBC bitmask, ensure the value is not null before calling this method
  1553. internal bool TrySkipLongBytes(long num) {
  1554. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1555. int cbSkip = 0;
  1556. while (num > 0) {
  1557. cbSkip = (int)Math.Min((long)Int32.MaxValue, num);
  1558. if (!TryReadByteArray(null, 0, cbSkip)) {
  1559. return false;
  1560. }
  1561. num -= (long)cbSkip;
  1562. }
  1563. return true;
  1564. }
  1565. // Reads bytes from the buffer but doesn't return them, in effect simply deleting them.
  1566. internal bool TrySkipBytes(int num) {
  1567. Debug.Assert(_syncOverAsync || !_asyncReadWithoutSnapshot, "This method is not safe to call when doing sync over async");
  1568. return TryReadByteArray(null, 0, num);
  1569. }
  1570. /////////////////////////////////////////
  1571. // Network/Packet Reading & Processing //
  1572. /////////////////////////////////////////
  1573. internal void SetSnapshot() {
  1574. _snapshot = new StateSnapshot(this);
  1575. _snapshot.Snap();
  1576. _snapshotReplay = false;
  1577. }
  1578. internal void ResetSnapshot() {
  1579. _snapshot = null;
  1580. _snapshotReplay = false;
  1581. }
  1582. #if DEBUG
  1583. StackTrace _lastStack;
  1584. #endif
  1585. internal bool TryReadNetworkPacket()
  1586. {
  1587. TdsParser.ReliabilitySection.Assert("unreliable call to TryReadNetworkPacket"); // you need to setup for a thread abort somewhere before you call this method
  1588. #if DEBUG
  1589. Debug.Assert(!_shouldHaveEnoughData || _attentionSent, "Caller said there should be enough data, but we are currently reading a packet");
  1590. #endif
  1591. if (_snapshot != null) {
  1592. if (_snapshotReplay) {
  1593. if (_snapshot.Replay()) {
  1594. #if DEBUG
  1595. if (_checkNetworkPacketRetryStacks) {
  1596. _snapshot.CheckStack(new StackTrace());
  1597. }
  1598. #endif
  1599. Bid.Trace("<sc.TdsParser.ReadNetworkPacket|INFO|ADV> Async packet replay\n");
  1600. return true;
  1601. }
  1602. #if DEBUG
  1603. else {
  1604. if (_checkNetworkPacketRetryStacks) {
  1605. _lastStack = new StackTrace();
  1606. }
  1607. }
  1608. #endif
  1609. }
  1610. // previous buffer is in snapshot
  1611. _inBuff = new byte[_inBuff.Length];
  1612. }
  1613. if (_syncOverAsync) {
  1614. ReadSniSyncOverAsync();
  1615. return true;
  1616. }
  1617. ReadSni(new TaskCompletionSource<object>());
  1618. #if DEBUG
  1619. if (_failAsyncPends) {
  1620. throw new InvalidOperationException("Attempted to pend a read when _failAsyncPends test hook was enabled");
  1621. }
  1622. if (_forceSyncOverAsyncAfterFirstPend) {
  1623. _syncOverAsync = true;
  1624. }
  1625. #endif
  1626. Debug.Assert((_snapshot != null) ^ _asyncReadWithoutSnapshot, "Must have either _snapshot set up or _asyncReadWithoutSnapshot enabled (but not both) to pend a read");
  1627. return false;
  1628. }
  1629. internal void PrepareReplaySnapshot() {
  1630. _networkPacketTaskSource = null;
  1631. _snapshot.PrepareReplay();
  1632. }
  1633. internal void ReadSniSyncOverAsync() {
  1634. if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
  1635. throw ADP.ClosedConnectionError();
  1636. }
  1637. IntPtr readPacket = IntPtr.Zero;
  1638. UInt32 error;
  1639. RuntimeHelpers.PrepareConstrainedRegions();
  1640. bool shouldDecrement = false;
  1641. try {
  1642. TdsParser.ReliabilitySection.Assert("unreliable call to ReadSniSync"); // you need to setup for a thread abort somewhere before you call this method
  1643. Interlocked.Increment(ref _readingCount);
  1644. shouldDecrement = true;
  1645. SNIHandle handle = Handle;
  1646. if (handle == null) {
  1647. throw ADP.ClosedConnectionError();
  1648. }
  1649. error = SNINativeMethodWrapper.SNIReadSyncOverAsync(handle, ref readPacket, GetTimeoutRemaining());
  1650. Interlocked.Decrement(ref _readingCount);
  1651. shouldDecrement = false;
  1652. if (_parser.MARSOn) { // Only take reset lock on MARS and Async.
  1653. CheckSetResetConnectionState(error, CallbackType.Read);
  1654. }
  1655. if (TdsEnums.SNI_SUCCESS == error) { // Success - process results!
  1656. Debug.Assert(ADP.PtrZero != readPacket, "ReadNetworkPacket cannot be null in syncronous operation!");
  1657. ProcessSniPacket(readPacket, 0);
  1658. #if DEBUG
  1659. if (_forcePendingReadsToWaitForUser) {
  1660. _networkPacketTaskSource = new TaskCompletionSource<object>();
  1661. Thread.MemoryBarrier();
  1662. _networkPacketTaskSource.Task.Wait();
  1663. _networkPacketTaskSource = null;
  1664. }
  1665. #endif
  1666. }
  1667. else { // Failure!
  1668. Debug.Assert(IntPtr.Zero == readPacket, "unexpected readPacket without corresponding SNIPacketRelease");
  1669. ReadSniError(this, error);
  1670. }
  1671. }
  1672. finally {
  1673. if (shouldDecrement) {
  1674. Interlocked.Decrement(ref _readingCount);
  1675. }
  1676. if (readPacket != IntPtr.Zero) {
  1677. // Be sure to release packet, otherwise it will be leaked by native.
  1678. SNINativeMethodWrapper.SNIPacketRelease(readPacket);
  1679. }
  1680. AssertValidState();
  1681. }
  1682. }
  1683. internal void OnConnectionClosed() {
  1684. // the stateObj is not null, so the async invocation that registered this callback
  1685. // via the SqlReferenceCollection has not yet completed. We will look for a
  1686. // _networkPacketTaskSource and mark it faulted. If we don't find it, then
  1687. // TdsParserStateObject.ReadSni will abort when it does look to see if the parser
  1688. // is open. If we do, then when the call that created it completes and a continuation
  1689. // is registered, we will ensure the completion is called.
  1690. // Note, this effort is necessary because when the app domain is being unloaded,
  1691. // we don't get callback from SNI.
  1692. // first mark parser broken. This is to ensure that ReadSni will abort if it has
  1693. // not yet executed.
  1694. Parser.State = TdsParserState.Broken;
  1695. Parser.Connection.BreakConnection();
  1696. // Ensure that changing state occurs before checking _networkPacketTaskSource
  1697. Thread.MemoryBarrier();
  1698. // then check for networkPacketTaskSource
  1699. var taskSource = _networkPacketTaskSource;
  1700. if (taskSource != null) {
  1701. taskSource.TrySetException(ADP.ExceptionWithStackTrace(ADP.ClosedConnectionError()));
  1702. }
  1703. taskSource = _writeCompletionSource;
  1704. if (taskSource != null) {
  1705. taskSource.TrySetException(ADP.ExceptionWithStackTrace(ADP.ClosedConnectionError()));
  1706. }
  1707. }
  1708. private void OnTimeout(object state) {
  1709. if (!_internalTimeout) {
  1710. _internalTimeout = true;
  1711. // lock protects against Close and Cancel
  1712. lock (this) {
  1713. if (!_attentionSent) {
  1714. AddError(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, _parser.Connection.TimeoutErrorInternal.GetErrorMessage(), "", 0, TdsEnums.SNI_WAIT_TIMEOUT));
  1715. // Grab a reference to the _networkPacketTaskSource in case it becomes null while we are trying to use it
  1716. TaskCompletionSource<object> source = _networkPacketTaskSource;
  1717. if (_parser.Connection.IsInPool) {
  1718. // Dev11 Bug 390048 : Timing issue between OnTimeout and ReadAsyncCallback results in SqlClient's packet parsing going out of [....]
  1719. // We should never timeout if the connection is currently in the pool: the safest thing to do here is to doom the connection to avoid corruption
  1720. Debug.Assert(_parser.Connection.IsConnectionDoomed, "Timeout occurred while the connection is in the pool");
  1721. _parser.State = TdsParserState.Broken;
  1722. _parser.Connection.BreakConnection();
  1723. if (source != null) {
  1724. source.TrySetCanceled();
  1725. }
  1726. }
  1727. else if (_parser.State == TdsParserState.OpenLoggedIn) {
  1728. try {
  1729. SendAttention(mustTakeWriteLock: true);
  1730. }
  1731. catch (Exception e) {
  1732. if (!ADP.IsCatchableExceptionType(e)) {
  1733. throw;
  1734. }
  1735. // if unable to send attention, cancel the _networkPacketTaskSource to
  1736. // request the parser be broken. SNIWritePacket errors will already
  1737. // be in the _errors collection.
  1738. if (source != null) {
  1739. source.TrySetCanceled();
  1740. }
  1741. }
  1742. }
  1743. // If we still haven't received a packet then we don't want to actually close the connection
  1744. // from another thread, so complete the pending operation as cancelled, informing them to break it
  1745. if (source != null) {
  1746. Task.Delay(AttentionTimeoutSeconds * 1000).ContinueWith(_ => {
  1747. // Only break the connection if the read didn't finish
  1748. if (!source.Task.IsCompleted) {
  1749. int pendingCallback = IncrementPendingCallbacks();
  1750. RuntimeHelpers.PrepareConstrainedRegions();
  1751. try {
  1752. // If pendingCallback is at 3, then ReadAsyncCallback hasn't been called yet
  1753. // So it is safe for us to break the connection and cancel the Task (since we are not sure that ReadAsyncCallback will ever be called)
  1754. if ((pendingCallback == 3) && (!source.Task.IsCompleted)) {
  1755. Debug.Assert(source == _networkPacketTaskSource, "_networkPacketTaskSource which is being timed is not the current task source");
  1756. // Try to throw the timeout exception and store it in the task
  1757. bool exceptionStored = false;
  1758. try {
  1759. CheckThrowSNIException();
  1760. }
  1761. catch (Exception ex) {
  1762. if (source.TrySetException(ex)) {
  1763. exceptionStored = true;
  1764. }
  1765. }
  1766. // Ensure that the connection is no longer usable
  1767. // This is needed since the timeout error added above is non-fatal (and so throwing it won't break the connection)
  1768. _parser.State = TdsParserState.Broken;
  1769. _parser.Connection.BreakConnection();
  1770. // If we didn't get an exception (something else observed it?) then ensure that the task is cancelled
  1771. if (!exceptionStored) {
  1772. source.TrySetCanceled();
  1773. }
  1774. }
  1775. }
  1776. finally {
  1777. DecrementPendingCallbacks(release: false);
  1778. }
  1779. }
  1780. });
  1781. }
  1782. }
  1783. }
  1784. }
  1785. }
  1786. internal void ReadSni(TaskCompletionSource<object> completion) {
  1787. Debug.Assert(_networkPacketTaskSource == null || ((_asyncReadWithoutSnapshot) && (_networkPacketTaskSource.Task.IsCompleted)), "Pending async call or failed to replay snapshot when calling ReadSni");
  1788. _networkPacketTaskSource = completion;
  1789. // Ensure that setting the completion source is completed before checking the state
  1790. Thread.MemoryBarrier();
  1791. // We must check after assigning _networkPacketTaskSource to avoid ----s with
  1792. // SqlCommand.OnConnectionClosed
  1793. if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
  1794. throw ADP.ClosedConnectionError();
  1795. }
  1796. #if DEBUG
  1797. if (_forcePendingReadsToWaitForUser) {
  1798. _realNetworkPacketTaskSource = new TaskCompletionSource<object>();
  1799. }
  1800. #endif
  1801. IntPtr readPacket = IntPtr.Zero;
  1802. UInt32 error = 0;
  1803. RuntimeHelpers.PrepareConstrainedRegions();
  1804. try {
  1805. Debug.Assert(completion != null, "Async on but null asyncResult passed");
  1806. if (_networkPacketTimeout == null) {
  1807. _networkPacketTimeout = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
  1808. }
  1809. // -1 == Infinite
  1810. // 0 == Already timed out (NOTE: To simulate the same behavior as [....] we will only timeout on 0 if we receive an IO Pending from SNI)
  1811. // >0 == Actual timeout remaining
  1812. int msecsRemaining = GetTimeoutRemaining();
  1813. if (msecsRemaining > 0) {
  1814. ChangeNetworkPacketTimeout(msecsRemaining, Timeout.Infinite);
  1815. }
  1816. SNIHandle handle = null;
  1817. RuntimeHelpers.PrepareConstrainedRegions();
  1818. try {} finally {
  1819. Interlocked.Increment(ref _readingCount);
  1820. handle = Handle;
  1821. if (handle != null) {
  1822. IncrementPendingCallbacks();
  1823. error = SNINativeMethodWrapper.SNIReadAsync(handle, ref readPacket);
  1824. if (!(TdsEnums.SNI_SUCCESS == error || TdsEnums.SNI_SUCCESS_IO_PENDING == error)) {
  1825. DecrementPendingCallbacks(false); // Failure - we won't receive callback!
  1826. }
  1827. }
  1828. Interlocked.Decrement(ref _readingCount);
  1829. }
  1830. if (handle == null) {
  1831. throw ADP.ClosedConnectionError();
  1832. }
  1833. if (TdsEnums.SNI_SUCCESS == error) { // Success - process results!
  1834. Debug.Assert(ADP.PtrZero != readPacket, "ReadNetworkPacket should not have been null on this async operation!");
  1835. ReadAsyncCallback(ADP.PtrZero, readPacket, 0);
  1836. }
  1837. else if (TdsEnums.SNI_SUCCESS_IO_PENDING != error) { // FAILURE!
  1838. Debug.Assert(IntPtr.Zero == readPacket, "unexpected readPacket without corresponding SNIPacketRelease");
  1839. ReadSniError(this, error);
  1840. #if DEBUG
  1841. if ((_forcePendingReadsToWaitForUser) && (_realNetworkPacketTaskSource != null)) {
  1842. _realNetworkPacketTaskSource.TrySetResult(null);
  1843. }
  1844. else
  1845. #endif
  1846. {
  1847. _networkPacketTaskSource.TrySetResult(null);
  1848. }
  1849. // Disable timeout timer on error
  1850. ChangeNetworkPacketTimeout(Timeout.Infinite, Timeout.Infinite);
  1851. }
  1852. else if (msecsRemaining == 0) { // Got IO Pending, but we have no time left to wait
  1853. // Immediately schedule the timeout timer to fire
  1854. ChangeNetworkPacketTimeout(0, Timeout.Infinite);
  1855. }
  1856. // DO NOT HANDLE PENDING READ HERE - which is TdsEnums.SNI_SUCCESS_IO_PENDING state.
  1857. // That is handled by user who initiated async read, or by ReadNetworkPacket which is [....] over async.
  1858. }
  1859. finally {
  1860. if (readPacket != IntPtr.Zero) {
  1861. // Be sure to release packet, otherwise it will be leaked by native.
  1862. SNINativeMethodWrapper.SNIPacketRelease(readPacket);
  1863. }
  1864. AssertValidState();
  1865. }
  1866. }
  1867. /// <summary>
  1868. /// Checks to see if the underlying connection is still alive (used by connection pool resilency)
  1869. /// NOTE: This is not safe to do on a connection that is currently in use
  1870. /// NOTE: This will mark the connection as broken if it is found to be dead
  1871. /// </summary>
  1872. /// <param name="throwOnException">If true then an exception will be thrown if the connection is found to be dead, otherwise no exception will be thrown</param>
  1873. /// <returns>True if the connection is still alive, otherwise false</returns>
  1874. internal bool IsConnectionAlive(bool throwOnException)
  1875. {
  1876. Debug.Assert(_parser.Connection == null || _parser.Connection.Pool != null, "Shouldn't be calling IsConnectionAlive on non-pooled connections");
  1877. bool isAlive = true;
  1878. if (DateTime.UtcNow.Ticks - _lastSuccessfulIOTimer._value > CheckConnectionWindow) {
  1879. if ((_parser == null) || ((_parser.State == TdsParserState.Broken) || (_parser.State == TdsParserState.Closed))) {
  1880. isAlive = false;
  1881. if (throwOnException) {
  1882. throw SQL.ConnectionDoomed();
  1883. }
  1884. }
  1885. else if ((_pendingCallbacks > 1) || ((_parser.Connection != null) && (!_parser.Connection.IsInPool))) {
  1886. // This connection is currently in use, assume that the connection is 'alive'
  1887. // NOTE: SNICheckConnection is not currently supported for connections that are in use
  1888. Debug.Assert(true, "Call to IsConnectionAlive while connection is in use");
  1889. }
  1890. else {
  1891. UInt32 error;
  1892. IntPtr readPacket = IntPtr.Zero;
  1893. RuntimeHelpers.PrepareConstrainedRegions();
  1894. try {
  1895. TdsParser.ReliabilitySection.Assert("unreliable call to IsConnectionAlive"); // you need to setup for a thread abort somewhere before you call this method
  1896. SniContext = SniContext.Snix_Connect;
  1897. error = SNINativeMethodWrapper.SNICheckConnection(Handle);
  1898. if ((error != TdsEnums.SNI_SUCCESS) && (error != TdsEnums.SNI_WAIT_TIMEOUT)) {
  1899. // Connection is dead
  1900. Bid.Trace("<sc.TdsParser.IsConnectionAlive|Info> received error %d on idle connection\n", (int)error);
  1901. isAlive = false;
  1902. if (throwOnException) {
  1903. // Get the error from SNI so that we can throw the correct exception
  1904. AddError(_parser.ProcessSNIError(this));
  1905. ThrowExceptionAndWarning();
  1906. }
  1907. }
  1908. else {
  1909. _lastSuccessfulIOTimer._value = DateTime.UtcNow.Ticks;
  1910. }
  1911. }
  1912. finally {
  1913. if (readPacket != IntPtr.Zero) {
  1914. // Be sure to release packet, otherwise it will be leaked by native.
  1915. SNINativeMethodWrapper.SNIPacketRelease(readPacket);
  1916. }
  1917. }
  1918. }
  1919. }
  1920. return isAlive;
  1921. }
  1922. /// <summary>
  1923. /// Checks to see if the underlying connection is still valid (used by idle connection resiliency - for active connections)
  1924. /// NOTE: This is not safe to do on a connection that is currently in use
  1925. /// NOTE: This will mark the connection as broken if it is found to be dead
  1926. /// </summary>
  1927. /// <returns>True if the connection is still alive, otherwise false</returns>
  1928. internal bool ValidateSNIConnection() {
  1929. if ((_parser == null) || ((_parser.State == TdsParserState.Broken) || (_parser.State == TdsParserState.Closed))) {
  1930. return false;
  1931. }
  1932. if (DateTime.UtcNow.Ticks - _lastSuccessfulIOTimer._value <= CheckConnectionWindow) {
  1933. return true;
  1934. }
  1935. UInt32 error=TdsEnums.SNI_SUCCESS;
  1936. SniContext = SniContext.Snix_Connect;
  1937. try {
  1938. Interlocked.Increment(ref _readingCount);
  1939. SNIHandle handle = Handle;
  1940. if (handle != null) {
  1941. error = SNINativeMethodWrapper.SNICheckConnection(handle);
  1942. }
  1943. }
  1944. finally {
  1945. Interlocked.Decrement(ref _readingCount);
  1946. }
  1947. return (error == TdsEnums.SNI_SUCCESS) || (error == TdsEnums.SNI_WAIT_TIMEOUT);
  1948. }
  1949. // This method should only be called by ReadSni! If not - it may have problems with timeouts!
  1950. private void ReadSniError(TdsParserStateObject stateObj, UInt32 error) {
  1951. TdsParser.ReliabilitySection.Assert("unreliable call to ReadSniSyncError"); // you need to setup for a thread abort somewhere before you call this method
  1952. if (TdsEnums.SNI_WAIT_TIMEOUT == error) {
  1953. Debug.Assert(_syncOverAsync, "Should never reach here with async on!");
  1954. bool fail = false;
  1955. if (_internalTimeout) { // This is now our second timeout - time to give up.
  1956. fail = true;
  1957. }
  1958. else {
  1959. stateObj._internalTimeout = true;
  1960. Debug.Assert(_parser.Connection != null, "SqlConnectionInternalTds handler can not be null at this point.");
  1961. AddError(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, _parser.Connection.TimeoutErrorInternal.GetErrorMessage(), "", 0, TdsEnums.SNI_WAIT_TIMEOUT));
  1962. if (!stateObj._attentionSent) {
  1963. if (stateObj.Parser.State == TdsParserState.OpenLoggedIn) {
  1964. stateObj.SendAttention(mustTakeWriteLock: true);
  1965. IntPtr syncReadPacket = IntPtr.Zero;
  1966. RuntimeHelpers.PrepareConstrainedRegions();
  1967. bool shouldDecrement = false;
  1968. try {
  1969. Interlocked.Increment(ref _readingCount);
  1970. shouldDecrement = true;
  1971. SNIHandle handle = Handle;
  1972. if (handle == null) {
  1973. throw ADP.ClosedConnectionError();
  1974. }
  1975. error = SNINativeMethodWrapper.SNIReadSyncOverAsync(handle, ref syncReadPacket, stateObj.GetTimeoutRemaining());
  1976. Interlocked.Decrement(ref _readingCount);
  1977. shouldDecrement = false;
  1978. if (TdsEnums.SNI_SUCCESS == error) {
  1979. // We will end up letting the run method deal with the expected done:done_attn token stream.
  1980. stateObj.ProcessSniPacket(syncReadPacket, 0);
  1981. return;
  1982. }
  1983. else {
  1984. Debug.Assert(IntPtr.Zero == syncReadPacket, "unexpected syncReadPacket without corresponding SNIPacketRelease");
  1985. fail = true; // Subsequent read failed, time to give up.
  1986. }
  1987. }
  1988. finally {
  1989. if (shouldDecrement) {
  1990. Interlocked.Decrement(ref _readingCount);
  1991. }
  1992. if (syncReadPacket != IntPtr.Zero) {
  1993. // Be sure to release packet, otherwise it will be leaked by native.
  1994. SNINativeMethodWrapper.SNIPacketRelease(syncReadPacket);
  1995. }
  1996. }
  1997. }
  1998. else {
  1999. if (_parser._loginWithFailover)
  2000. {
  2001. // For DB Mirroring Failover during login, never break the connection, just close the TdsParser (Devdiv 846298)
  2002. _parser.Disconnect();
  2003. }
  2004. else if ((_parser.State == TdsParserState.OpenNotLoggedIn) && (_parser.Connection.ConnectionOptions.MultiSubnetFailover || _parser.Connection.ConnectionOptions.TransparentNetworkIPResolution))
  2005. {
  2006. // For MultiSubnet Failover during login, never break the connection, just close the TdsParser
  2007. _parser.Disconnect();
  2008. }
  2009. else
  2010. fail = true; // We aren't yet logged in - just fail.
  2011. }
  2012. }
  2013. }
  2014. if (fail) {
  2015. _parser.State = TdsParserState.Broken; // We failed subsequent read, we have to quit!
  2016. _parser.Connection.BreakConnection();
  2017. }
  2018. }
  2019. else {
  2020. // Caution: ProcessSNIError always returns a fatal error!
  2021. AddError(_parser.ProcessSNIError(stateObj));
  2022. }
  2023. ThrowExceptionAndWarning();
  2024. AssertValidState();
  2025. }
  2026. //
  2027. public void ProcessSniPacket(IntPtr packet, UInt32 error) {
  2028. if (error != 0) {
  2029. if ((_parser.State == TdsParserState.Closed) || (_parser.State == TdsParserState.Broken)) {
  2030. // Do nothing with with callback if closed or broken and error not 0 - callback can occur
  2031. // after connection has been closed. PROBLEM IN NETLIB - DESIGN FLAW.
  2032. return;
  2033. }
  2034. AddError(_parser.ProcessSNIError(this));
  2035. AssertValidState();
  2036. }
  2037. else {
  2038. UInt32 dataSize = 0;
  2039. UInt32 getDataError = SNINativeMethodWrapper.SNIPacketGetData(packet, _inBuff, ref dataSize);
  2040. if (getDataError == TdsEnums.SNI_SUCCESS) {
  2041. if (_inBuff.Length < dataSize) {
  2042. Debug.Assert(true, "Unexpected dataSize on Read");
  2043. throw SQL.InvalidInternalPacketSize (Res.GetString(Res.SqlMisc_InvalidArraySizeMessage));
  2044. }
  2045. _lastSuccessfulIOTimer._value = DateTime.UtcNow.Ticks;
  2046. _inBytesRead = (int)dataSize;
  2047. _inBytesUsed = 0;
  2048. if (_snapshot != null) {
  2049. _snapshot.PushBuffer(_inBuff, _inBytesRead);
  2050. if (_snapshotReplay) {
  2051. _snapshot.Replay();
  2052. #if DEBUG
  2053. _snapshot.AssertCurrent();
  2054. #endif
  2055. }
  2056. }
  2057. SniReadStatisticsAndTracing();
  2058. if (Bid.AdvancedOn) {
  2059. Bid.TraceBin("<sc.TdsParser.ReadNetworkPacketAsyncCallback|INFO|ADV> Packet read", _inBuff, (UInt16)_inBytesRead);
  2060. }
  2061. AssertValidState();
  2062. }
  2063. else {
  2064. throw SQL.ParsingError(ParsingErrorState.ProcessSniPacketFailed);
  2065. }
  2066. }
  2067. }
  2068. private void ChangeNetworkPacketTimeout(int dueTime, int period) {
  2069. Timer networkPacketTimeout = _networkPacketTimeout;
  2070. if (networkPacketTimeout != null) {
  2071. try {
  2072. networkPacketTimeout.Change(dueTime, period);
  2073. }
  2074. catch (ObjectDisposedException) {
  2075. // _networkPacketTimeout is set to null before Disposing, but there is still a slight chance
  2076. // that object was disposed after we took a copy
  2077. }
  2078. }
  2079. }
  2080. public void ReadAsyncCallback(IntPtr key, IntPtr packet, UInt32 error) { // Key never used.
  2081. // Note - it's possible that when native calls managed that an asynchronous exception
  2082. // could occur in the native->managed transition, which would
  2083. // have two impacts:
  2084. // 1) user event not called
  2085. // 2) DecrementPendingCallbacks not called, which would mean this object would be leaked due
  2086. // to the outstanding GCRoot until AppDomain.Unload.
  2087. // We live with the above for the time being due to the constraints of the current
  2088. // reliability infrastructure provided by the CLR.
  2089. TaskCompletionSource<object> source = _networkPacketTaskSource;
  2090. #if DEBUG
  2091. if ((_forcePendingReadsToWaitForUser) && (_realNetworkPacketTaskSource != null)) {
  2092. source = _realNetworkPacketTaskSource;
  2093. }
  2094. #endif
  2095. // The mars physical connection can get a callback
  2096. // with a packet but no result after the connection is closed.
  2097. if (source == null && _parser._pMarsPhysicalConObj == this) {
  2098. return;
  2099. }
  2100. RuntimeHelpers.PrepareConstrainedRegions();
  2101. bool processFinallyBlock = true;
  2102. try {
  2103. Debug.Assert(IntPtr.Zero == packet || IntPtr.Zero != packet && source != null, "AsyncResult null on callback");
  2104. if (_parser.MARSOn) { // Only take reset lock on MARS and Async.
  2105. CheckSetResetConnectionState(error, CallbackType.Read);
  2106. }
  2107. ChangeNetworkPacketTimeout(Timeout.Infinite, Timeout.Infinite);
  2108. ProcessSniPacket(packet, error);
  2109. }
  2110. catch (Exception e) {
  2111. processFinallyBlock = ADP.IsCatchableExceptionType(e);
  2112. throw;
  2113. }
  2114. finally {
  2115. // pendingCallbacks may be 2 after decrementing, this indicates that a fatal timeout is occuring, and therefore we shouldn't complete the task
  2116. int pendingCallbacks = DecrementPendingCallbacks(false); // may dispose of GC handle.
  2117. if ((processFinallyBlock) && (source != null) && (pendingCallbacks < 2)) {
  2118. if (error == 0) {
  2119. if (_executionContext != null) {
  2120. ExecutionContext.Run(_executionContext, (state) => source.TrySetResult(null), null);
  2121. }
  2122. else {
  2123. source.TrySetResult(null);
  2124. }
  2125. }
  2126. else {
  2127. if (_executionContext != null) {
  2128. ExecutionContext.Run(_executionContext, (state) => ReadAsyncCallbackCaptureException(source), null);
  2129. }
  2130. else {
  2131. ReadAsyncCallbackCaptureException(source);
  2132. }
  2133. }
  2134. }
  2135. AssertValidState();
  2136. }
  2137. }
  2138. private void ReadAsyncCallbackCaptureException(TaskCompletionSource<object> source) {
  2139. bool captureSuccess = false;
  2140. try {
  2141. if (_hasErrorOrWarning) {
  2142. // Do the close on another thread, since we don't want to block the callback thread
  2143. ThrowExceptionAndWarning(asyncClose: true);
  2144. }
  2145. else if ((_parser.State == TdsParserState.Closed) || (_parser.State == TdsParserState.Broken)) {
  2146. // Connection was closed by another thread before we parsed the packet, so no error was added to the collection
  2147. throw ADP.ClosedConnectionError();
  2148. }
  2149. }
  2150. catch (Exception ex) {
  2151. if (source.TrySetException(ex)) {
  2152. // There was an exception, and it was successfully stored in the task
  2153. captureSuccess = true;
  2154. }
  2155. }
  2156. if (!captureSuccess) {
  2157. // Either there was no exception, or the task was already completed
  2158. // This is unusual, but possible if a fatal timeout occured on another thread (which should mean that the connection is now broken)
  2159. Debug.Assert(_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed || _parser.Connection.IsConnectionDoomed, "Failed to capture exception while the connection was still healthy");
  2160. // The safest thing to do is to ensure that the connection is broken and attempt to cancel the task
  2161. // This must be done from another thread to not block the callback thread
  2162. Task.Factory.StartNew(() => {
  2163. _parser.State = TdsParserState.Broken;
  2164. _parser.Connection.BreakConnection();
  2165. source.TrySetCanceled();
  2166. });
  2167. }
  2168. }
  2169. #pragma warning disable 420 // a reference to a volatile field will not be treated as volatile
  2170. public void WriteAsyncCallback(IntPtr key, IntPtr packet, UInt32 sniError) { // Key never used.
  2171. RemovePacketFromPendingList(packet);
  2172. try {
  2173. if (sniError != TdsEnums.SNI_SUCCESS) {
  2174. Bid.Trace("<sc.TdsParser.WriteAsyncCallback|Info> write async returned error code %d\n", (int)sniError);
  2175. try {
  2176. AddError(_parser.ProcessSNIError(this));
  2177. ThrowExceptionAndWarning(asyncClose: true);
  2178. }
  2179. catch (Exception e) {
  2180. var writeCompletionSource = _writeCompletionSource;
  2181. if (writeCompletionSource != null) {
  2182. writeCompletionSource.TrySetException(e);
  2183. }
  2184. else {
  2185. _delayedWriteAsyncCallbackException = e;
  2186. // Ensure that _delayedWriteAsyncCallbackException is set before checking _writeCompletionSource
  2187. Thread.MemoryBarrier();
  2188. // Double check that _writeCompletionSource hasn't been created in the meantime
  2189. writeCompletionSource = _writeCompletionSource;
  2190. if (writeCompletionSource != null) {
  2191. var delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null);
  2192. if (delayedException != null) {
  2193. writeCompletionSource.TrySetException(delayedException);
  2194. }
  2195. }
  2196. }
  2197. return;
  2198. }
  2199. }
  2200. else {
  2201. _lastSuccessfulIOTimer._value = DateTime.UtcNow.Ticks;
  2202. }
  2203. }
  2204. finally {
  2205. #if DEBUG
  2206. if (SqlCommand.DebugForceAsyncWriteDelay > 0) {
  2207. new Timer(obj => {
  2208. Interlocked.Decrement(ref _asyncWriteCount);
  2209. var writeCompletionSource = _writeCompletionSource;
  2210. if (_asyncWriteCount == 0 && writeCompletionSource != null) {
  2211. writeCompletionSource.TrySetResult(null);
  2212. }
  2213. }, null, SqlCommand.DebugForceAsyncWriteDelay, Timeout.Infinite);
  2214. }
  2215. else {
  2216. #else
  2217. {
  2218. #endif
  2219. Interlocked.Decrement(ref _asyncWriteCount);
  2220. }
  2221. }
  2222. #if DEBUG
  2223. if (SqlCommand.DebugForceAsyncWriteDelay > 0) {
  2224. return;
  2225. }
  2226. #endif
  2227. var completionSource = _writeCompletionSource;
  2228. if (_asyncWriteCount == 0 && completionSource != null) {
  2229. completionSource.TrySetResult(null);
  2230. }
  2231. }
  2232. #pragma warning restore 420
  2233. /////////////////////////////////////////
  2234. // Network/Packet Writing & Processing //
  2235. /////////////////////////////////////////
  2236. //
  2237. // Takes a secure string and offsets and saves them for a write latter when the information is written out to SNI Packet
  2238. // This method is provided to better handle the life cycle of the clear text of the secure string
  2239. // This method also ensures that the clear text is not held in the unpined managed buffer so that it avoids getting moved around by CLR garbage collector
  2240. // TdsParserStaticMethods.EncryptPassword operation is also done in the unmanaged buffer for the clear text later
  2241. //
  2242. internal void WriteSecureString(SecureString secureString) {
  2243. TdsParser.ReliabilitySection.Assert("unreliable call to WriteSecureString"); // you need to setup for a thread abort somewhere before you call this method
  2244. Debug.Assert(_securePasswords[0] == null || _securePasswords[1] == null, "There are more than two secure passwords");
  2245. int index = _securePasswords[0] != null ? 1 : 0;
  2246. _securePasswords[index] = secureString;
  2247. _securePasswordOffsetsInBuffer[index] = _outBytesUsed;
  2248. // loop through and write the entire array
  2249. int lengthInBytes = secureString.Length * 2;
  2250. // It is guaranteed both secure password and secure change password should fit into the first packet
  2251. // Given current TDS format and implementation it is not possible that one of secure string is the last item and exactly fill up the output buffer
  2252. // if this ever happens and it is correct situation, the packet needs to be written out after _outBytesUsed is update
  2253. Debug.Assert((_outBytesUsed + lengthInBytes) < _outBuff.Length, "Passwords cannot be splited into two different packet or the last item which fully fill up _outBuff!!!");
  2254. _outBytesUsed += lengthInBytes;
  2255. }
  2256. // ResetSecurePasswordsInformation: clears information regarding secure passwords when login is done; called from TdsParser.TdsLogin
  2257. internal void ResetSecurePasswordsInfomation() {
  2258. for (int i = 0; i < _securePasswords.Length; ++i) {
  2259. _securePasswords[i] = null;
  2260. _securePasswordOffsetsInBuffer[i] = 0;
  2261. }
  2262. }
  2263. internal Task WaitForAccumulatedWrites( ) {
  2264. // Checked for stored exceptions
  2265. #pragma warning disable 420 // A reference to a volatile field will not be treated as volatile - Disabling since the Interlocked APIs are volatile aware
  2266. var delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null);
  2267. if (delayedException != null) {
  2268. throw delayedException;
  2269. }
  2270. #pragma warning restore 420
  2271. if (_asyncWriteCount == 0) {
  2272. return null;
  2273. }
  2274. _writeCompletionSource = new TaskCompletionSource<object>();
  2275. Task task = _writeCompletionSource.Task;
  2276. // Ensure that _writeCompletionSource is set before checking state
  2277. Thread.MemoryBarrier();
  2278. // Now that we have set _writeCompletionSource, check if parser is closed or broken
  2279. if ((_parser.State == TdsParserState.Closed) || (_parser.State == TdsParserState.Broken)) {
  2280. throw ADP.ClosedConnectionError();
  2281. }
  2282. // Check for stored exceptions
  2283. #pragma warning disable 420 // A reference to a volatile field will not be treated as volatile - Disabling since the Interlocked APIs are volatile aware
  2284. delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null);
  2285. if (delayedException != null) {
  2286. throw delayedException;
  2287. }
  2288. #pragma warning restore 420
  2289. // If there are no outstanding writes, see if we can shortcut and return null
  2290. if ((_asyncWriteCount == 0) && ((!task.IsCompleted) || (task.Exception == null))) {
  2291. task = null;
  2292. }
  2293. return task;
  2294. }
  2295. // Takes in a single byte and writes it to the buffer. If the buffer is full, it is flushed
  2296. // and then the buffer is re-initialized in flush() and then the byte is put in the buffer.
  2297. internal void WriteByte(byte b) {
  2298. TdsParser.ReliabilitySection.Assert("unreliable call to WriteByte"); // you need to setup for a thread abort somewhere before you call this method
  2299. Debug.Assert(_outBytesUsed <= _outBuff.Length, "ERROR - TDSParser: _outBytesUsed > _outBuff.Length");
  2300. // check to make sure we haven't used the full amount of space available in the buffer, if so, flush it
  2301. if (_outBytesUsed == _outBuff.Length) {
  2302. WritePacket(TdsEnums.SOFTFLUSH, canAccumulate:true);
  2303. }
  2304. // set byte in buffer and increment the counter for number of bytes used in the out buffer
  2305. _outBuff[_outBytesUsed++] = b;
  2306. }
  2307. //
  2308. // Takes a byte array and writes it to the buffer.
  2309. //
  2310. internal Task WriteByteArray(Byte[] b, int len, int offsetBuffer, bool canAccumulate=true, TaskCompletionSource<object> completion = null) {
  2311. try {
  2312. TdsParser.ReliabilitySection.Assert("unreliable call to WriteByteArray"); // you need to setup for a thread abort somewhere before you call this method
  2313. bool async = _parser._asyncWrite; // NOTE: We are capturing this now for the assert after the Task is returned, since WritePacket will turn off async if there is an exception
  2314. Debug.Assert(async || _asyncWriteCount == 0);
  2315. // Do we have to send out in packet size chunks, or can we rely on netlib layer to break it up?
  2316. // would prefer to to do something like:
  2317. //
  2318. // if (len > what we have room for || len > out buf)
  2319. // flush buffer
  2320. // UnsafeNativeMethods.Write(b)
  2321. //
  2322. int offset = offsetBuffer;
  2323. Debug.Assert(b.Length >= len, "Invalid length sent to WriteByteArray()!");
  2324. // loop through and write the entire array
  2325. do {
  2326. if ((_outBytesUsed + len) > _outBuff.Length) {
  2327. // If the remainder of the string won't fit into the buffer, then we have to put
  2328. // whatever we can into the buffer, and flush that so we can then put more into
  2329. // the buffer on the next loop of the while.
  2330. int remainder = _outBuff.Length - _outBytesUsed;
  2331. // write the remainder
  2332. Buffer.BlockCopy(b, offset, _outBuff, _outBytesUsed, remainder);
  2333. // handle counters
  2334. offset += remainder;
  2335. _outBytesUsed += remainder;
  2336. len -= remainder;
  2337. Task packetTask = WritePacket(TdsEnums.SOFTFLUSH, canAccumulate);
  2338. if (packetTask != null) {
  2339. Task task = null;
  2340. Debug.Assert(async, "Returned task in sync mode");
  2341. if (completion == null) {
  2342. completion = new TaskCompletionSource<object>();
  2343. task = completion.Task; // we only care about return from topmost call, so do not access Task property in other cases
  2344. }
  2345. WriteByteArraySetupContinuation(b, len, completion, offset, packetTask);
  2346. return task;
  2347. }
  2348. }
  2349. else { //((stateObj._outBytesUsed + len) <= stateObj._outBuff.Length )
  2350. // Else the remainder of the string will fit into the buffer, so copy it into the
  2351. // buffer and then break out of the loop.
  2352. Buffer.BlockCopy(b, offset, _outBuff, _outBytesUsed, len);
  2353. // handle out buffer bytes used counter
  2354. _outBytesUsed += len;
  2355. break;
  2356. }
  2357. } while (len > 0);
  2358. if (completion != null) {
  2359. completion.SetResult(null);
  2360. }
  2361. return null;
  2362. }
  2363. catch (Exception e) {
  2364. if (completion != null) {
  2365. completion.SetException(e);
  2366. return null;
  2367. }
  2368. else {
  2369. throw;
  2370. }
  2371. }
  2372. }
  2373. // This is in its own method to avoid always allocating the lambda in WriteByteArray
  2374. private void WriteByteArraySetupContinuation(Byte[] b, int len, TaskCompletionSource<object> completion, int offset, Task packetTask) {
  2375. AsyncHelper.ContinueTask(packetTask, completion,
  2376. () => WriteByteArray(b, len: len, offsetBuffer: offset, canAccumulate: false, completion: completion),
  2377. connectionToDoom: _parser.Connection);
  2378. }
  2379. // Dumps contents of buffer to SNI for network write.
  2380. internal Task WritePacket(byte flushMode, bool canAccumulate = false) {
  2381. if ((_parser.State == TdsParserState.Closed) || (_parser.State == TdsParserState.Broken)) {
  2382. throw ADP.ClosedConnectionError();
  2383. }
  2384. if (_parser.IsYukonOrNewer && !_bulkCopyOpperationInProgress // ignore the condition checking for bulk copy (SQL BU 414551)
  2385. && _outBytesUsed == (_outputHeaderLen + BitConverter.ToInt32(_outBuff, _outputHeaderLen))
  2386. && _outputPacketNumber == 1
  2387. || _outBytesUsed == _outputHeaderLen
  2388. && _outputPacketNumber == 1) {
  2389. return null;
  2390. }
  2391. byte status;
  2392. byte packetNumber = _outputPacketNumber;
  2393. // Set Status byte based whether this is end of message or not
  2394. bool willCancel = (_cancelled) && (_parser._asyncWrite);
  2395. if (willCancel) {
  2396. status = TdsEnums.ST_EOM | TdsEnums.ST_IGNORE;
  2397. _outputPacketNumber = 1;
  2398. }
  2399. else if (TdsEnums.HARDFLUSH == flushMode) {
  2400. status = TdsEnums.ST_EOM;
  2401. _outputPacketNumber = 1; // end of message - reset to 1 - per ramas
  2402. }
  2403. else if (TdsEnums.SOFTFLUSH==flushMode) {
  2404. status = TdsEnums.ST_BATCH;
  2405. _outputPacketNumber++;
  2406. }
  2407. else {
  2408. status = TdsEnums.ST_EOM;
  2409. Debug.Assert (false, String.Format((IFormatProvider)null, "Unexpected argument {0,-2:x2} to WritePacket", flushMode));
  2410. }
  2411. _outBuff[0] = _outputMessageType; // Message Type
  2412. _outBuff[1] = status;
  2413. _outBuff[2] = (byte)(_outBytesUsed >> 8); // length - upper byte
  2414. _outBuff[3] = (byte)(_outBytesUsed&0xff); // length - lower byte
  2415. _outBuff[4] = 0; // channel
  2416. _outBuff[5] = 0;
  2417. _outBuff[6] = packetNumber; // packet
  2418. _outBuff[7] = 0; // window
  2419. Task task=null;
  2420. _parser.CheckResetConnection(this); // HAS SIDE EFFECTS - re-org at a later time if possible
  2421. task = WriteSni(canAccumulate);
  2422. AssertValidState();
  2423. if (willCancel) {
  2424. // If we have been cancelled, then ensure that we write the ATTN packet as well
  2425. task = AsyncHelper.CreateContinuationTask(task, CancelWritePacket, _parser.Connection);
  2426. }
  2427. return task;
  2428. }
  2429. private void CancelWritePacket() {
  2430. Debug.Assert(_cancelled, "Should not call CancelWritePacket if _cancelled is not set");
  2431. _parser.Connection.ThreadHasParserLockForClose = true; // In case of error, let the connection know that we are holding the lock
  2432. try {
  2433. // Send the attention and wait for the ATTN_ACK
  2434. SendAttention();
  2435. ResetCancelAndProcessAttention();
  2436. // Let the caller know that we've given up
  2437. throw SQL.OperationCancelled();
  2438. }
  2439. finally {
  2440. _parser.Connection.ThreadHasParserLockForClose = false;
  2441. }
  2442. }
  2443. #pragma warning disable 420 // a reference to a volatile field will not be treated as volatile
  2444. private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniError, bool canAccumulate, bool callerHasConnectionLock) {
  2445. // Check for a stored exception
  2446. var delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null);
  2447. if (delayedException != null) {
  2448. throw delayedException;
  2449. }
  2450. Task task = null;
  2451. _writeCompletionSource = null;
  2452. IntPtr packetPointer = IntPtr.Zero;
  2453. bool sync = !_parser._asyncWrite;
  2454. if (sync && _asyncWriteCount > 0) { // for example, SendAttention while there are writes pending
  2455. Task waitForWrites = WaitForAccumulatedWrites();
  2456. if (waitForWrites != null) {
  2457. try {
  2458. waitForWrites.Wait();
  2459. }
  2460. catch (AggregateException ae) {
  2461. throw ae.InnerException;
  2462. }
  2463. }
  2464. Debug.Assert(_asyncWriteCount == 0, "All async write should be finished");
  2465. }
  2466. if (!sync) {
  2467. // Add packet to the pending list (since the callback can happen any time after we call SNIWritePacket)
  2468. packetPointer = AddPacketToPendingList(packet);
  2469. }
  2470. // Async operation completion may be delayed (success pending).
  2471. RuntimeHelpers.PrepareConstrainedRegions();
  2472. try {
  2473. }
  2474. finally {
  2475. sniError = SNINativeMethodWrapper.SNIWritePacket(handle, packet, sync);
  2476. }
  2477. if (sniError == TdsEnums.SNI_SUCCESS_IO_PENDING) {
  2478. Debug.Assert(!sync, "Completion should be handled in SniManagedWwrapper");
  2479. Interlocked.Increment(ref _asyncWriteCount);
  2480. Debug.Assert(_asyncWriteCount >= 0);
  2481. if (!canAccumulate) {
  2482. // Create completion source (for callback to complete)
  2483. _writeCompletionSource = new TaskCompletionSource<object>();
  2484. task = _writeCompletionSource.Task;
  2485. // Ensure that setting _writeCompletionSource completes before checking _delayedWriteAsyncCallbackException
  2486. Thread.MemoryBarrier();
  2487. // Check for a stored exception
  2488. delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null);
  2489. if (delayedException != null) {
  2490. throw delayedException;
  2491. }
  2492. // If there are no outstanding writes, see if we can shortcut and return null
  2493. if ((_asyncWriteCount == 0) && ((!task.IsCompleted) || (task.Exception == null))) {
  2494. task = null;
  2495. }
  2496. }
  2497. }
  2498. #if DEBUG
  2499. else if (!sync && !canAccumulate && SqlCommand.DebugForceAsyncWriteDelay > 0) {
  2500. // Executed synchronously - callback will not be called
  2501. TaskCompletionSource<object> completion = new TaskCompletionSource<object>();
  2502. uint error = sniError;
  2503. new Timer(obj=>{
  2504. try {
  2505. if (_parser.MARSOn) { // Only take reset lock on MARS.
  2506. CheckSetResetConnectionState(error, CallbackType.Write);
  2507. }
  2508. if (error != TdsEnums.SNI_SUCCESS) {
  2509. Bid.Trace("<sc.TdsParser.WritePacket|Info> write async returned error code %d\n", (int)error);
  2510. AddError(_parser.ProcessSNIError(this));
  2511. ThrowExceptionAndWarning();
  2512. }
  2513. AssertValidState();
  2514. completion.SetResult(null);
  2515. }
  2516. catch (Exception e) {
  2517. completion.SetException(e);
  2518. }
  2519. },null,SqlCommand.DebugForceAsyncWriteDelay,Timeout.Infinite);
  2520. task = completion.Task;
  2521. }
  2522. #endif
  2523. else {
  2524. if (_parser.MARSOn) { // Only take reset lock on MARS.
  2525. CheckSetResetConnectionState(sniError, CallbackType.Write);
  2526. }
  2527. if (sniError == TdsEnums.SNI_SUCCESS) {
  2528. _lastSuccessfulIOTimer._value = DateTime.UtcNow.Ticks;
  2529. if (!sync) {
  2530. // Since there will be no callback, remove the packet from the pending list
  2531. Debug.Assert(packetPointer != IntPtr.Zero, "Packet added to list has an invalid pointer, can not remove from pending list");
  2532. RemovePacketFromPendingList(packetPointer);
  2533. }
  2534. }
  2535. else {
  2536. Bid.Trace("<sc.TdsParser.WritePacket|Info> write async returned error code %d\n", (int)sniError);
  2537. AddError(_parser.ProcessSNIError(this));
  2538. ThrowExceptionAndWarning(callerHasConnectionLock);
  2539. }
  2540. AssertValidState();
  2541. }
  2542. return task;
  2543. }
  2544. #pragma warning restore 420
  2545. // Sends an attention signal - executing thread will consume attn.
  2546. internal void SendAttention(bool mustTakeWriteLock = false) {
  2547. if (!_attentionSent) {
  2548. // Dumps contents of buffer to OOB write (currently only used for
  2549. // attentions. There is no body for this message
  2550. // Doesn't touch this._outBytesUsed
  2551. if (_parser.State == TdsParserState.Closed || _parser.State == TdsParserState.Broken) {
  2552. return;
  2553. }
  2554. SNIPacket attnPacket = new SNIPacket(Handle);
  2555. _sniAsyncAttnPacket = attnPacket;
  2556. SNINativeMethodWrapper.SNIPacketSetData(attnPacket, SQL.AttentionHeader, TdsEnums.HEADER_LEN, null, null);
  2557. RuntimeHelpers.PrepareConstrainedRegions();
  2558. try {
  2559. // Dev11 #344723: SqlClient stress hang System_Data!Tcp::ReadSync via a call to SqlDataReader::Close
  2560. // Set _attentionSending to true before sending attention and reset after setting _attentionSent
  2561. // This prevents a race condition between receiving the attention ACK and setting _attentionSent
  2562. _attentionSending = true;
  2563. #if DEBUG
  2564. if (!_skipSendAttention)
  2565. {
  2566. #endif
  2567. // Take lock and send attention
  2568. bool releaseLock = false;
  2569. if ((mustTakeWriteLock) && (!_parser.Connection.ThreadHasParserLockForClose)) {
  2570. releaseLock = true;
  2571. _parser.Connection._parserLock.Wait(canReleaseFromAnyThread: false);
  2572. _parser.Connection.ThreadHasParserLockForClose = true;
  2573. }
  2574. try {
  2575. // Check again (just in case the connection was closed while we were waiting)
  2576. if (_parser.State == TdsParserState.Closed || _parser.State == TdsParserState.Broken) {
  2577. return;
  2578. }
  2579. UInt32 sniError;
  2580. _parser._asyncWrite = false; // stop async write
  2581. SNIWritePacket(Handle, attnPacket, out sniError, canAccumulate:false, callerHasConnectionLock: false);
  2582. Bid.Trace("<sc.TdsParser.SendAttention|Info> Send Attention ASync .\n");
  2583. }
  2584. finally {
  2585. if (releaseLock) {
  2586. _parser.Connection.ThreadHasParserLockForClose = false;
  2587. _parser.Connection._parserLock.Release();
  2588. }
  2589. }
  2590. #if DEBUG
  2591. }
  2592. #endif
  2593. SetTimeoutSeconds(AttentionTimeoutSeconds); // Initialize new attention timeout of 5 seconds.
  2594. _attentionSent = true;
  2595. }
  2596. finally {
  2597. _attentionSending = false;
  2598. }
  2599. if (Bid.AdvancedOn) {
  2600. Bid.TraceBin("<sc.TdsParser.WritePacket|INFO|ADV> Packet sent", _outBuff, (UInt16)_outBytesUsed);
  2601. }
  2602. Bid.Trace("<sc.TdsParser.SendAttention|Info> Attention sent to the server.\n");
  2603. AssertValidState();
  2604. }
  2605. }
  2606. private Task WriteSni(bool canAccumulate) {
  2607. // Prepare packet, and write to packet.
  2608. SNIPacket packet = GetResetWritePacket();
  2609. SNINativeMethodWrapper.SNIPacketSetData(packet, _outBuff, _outBytesUsed, _securePasswords, _securePasswordOffsetsInBuffer);
  2610. uint sniError;
  2611. Debug.Assert(Parser.Connection._parserLock.ThreadMayHaveLock(), "Thread is writing without taking the connection lock");
  2612. Task task = SNIWritePacket(Handle, packet, out sniError, canAccumulate, callerHasConnectionLock: true);
  2613. // Check to see if the timeout has occured. This time out code is special case code to allow BCP writes to timeout to fix bug 350558, eventually we should make all writes timeout.
  2614. if (_bulkCopyOpperationInProgress && 0 == GetTimeoutRemaining()) {
  2615. _parser.Connection.ThreadHasParserLockForClose = true;
  2616. try {
  2617. Debug.Assert(_parser.Connection != null, "SqlConnectionInternalTds handler can not be null at this point.");
  2618. AddError(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, _parser.Connection.TimeoutErrorInternal.GetErrorMessage(), "", 0, TdsEnums.SNI_WAIT_TIMEOUT));
  2619. _bulkCopyWriteTimeout = true;
  2620. SendAttention();
  2621. _parser.ProcessPendingAck(this);
  2622. ThrowExceptionAndWarning();
  2623. }
  2624. finally {
  2625. _parser.Connection.ThreadHasParserLockForClose = false;
  2626. }
  2627. }
  2628. // Special case logic for encryption removal.
  2629. //
  2630. if (_parser.State == TdsParserState.OpenNotLoggedIn &&
  2631. _parser.EncryptionOptions == EncryptionOptions.LOGIN) {
  2632. // If no error occurred, and we are Open but not logged in, and
  2633. // our encryptionOption state is login, remove the SSL Provider.
  2634. // We only need encrypt the very first packet of the login message to the server.
  2635. // SQL BU DT 332481 - we wanted to encrypt entire login channel, but there is
  2636. // currently no mechanism to communicate this. Removing encryption post 1st packet
  2637. // is a hard-coded agreement between client and server. We need some mechanism or
  2638. // common change to be able to make this change in a non-breaking fasion.
  2639. _parser.RemoveEncryption(); // Remove the SSL Provider.
  2640. _parser.EncryptionOptions = EncryptionOptions.OFF; // Turn encryption off.
  2641. // Since this packet was associated with encryption, dispose and re-create.
  2642. ClearAllWritePackets();
  2643. }
  2644. SniWriteStatisticsAndTracing();
  2645. ResetBuffer();
  2646. AssertValidState();
  2647. return task;
  2648. }
  2649. internal SNIPacket GetResetWritePacket() {
  2650. if (_sniPacket != null) {
  2651. SNINativeMethodWrapper.SNIPacketReset(Handle, SNINativeMethodWrapper.IOType.WRITE, _sniPacket, SNINativeMethodWrapper.ConsumerNumber.SNI_Consumer_SNI);
  2652. }
  2653. else {
  2654. lock (_writePacketLockObject) {
  2655. _sniPacket = _writePacketCache.Take(Handle);
  2656. }
  2657. }
  2658. return _sniPacket;
  2659. }
  2660. internal void ClearAllWritePackets() {
  2661. if (_sniPacket != null) {
  2662. _sniPacket.Dispose();
  2663. _sniPacket = null;
  2664. }
  2665. lock (_writePacketLockObject) {
  2666. Debug.Assert(_pendingWritePackets.Count == 0 && _asyncWriteCount == 0, "Should not clear all write packets if there are packets pending");
  2667. _writePacketCache.Clear();
  2668. }
  2669. }
  2670. private IntPtr AddPacketToPendingList(SNIPacket packet) {
  2671. Debug.Assert(packet == _sniPacket, "Adding a packet other than the current packet to the pending list");
  2672. _sniPacket = null;
  2673. IntPtr pointer = packet.DangerousGetHandle();
  2674. lock (_writePacketLockObject) {
  2675. _pendingWritePackets.Add(pointer, packet);
  2676. }
  2677. return pointer;
  2678. }
  2679. private void RemovePacketFromPendingList(IntPtr pointer) {
  2680. SNIPacket recoveredPacket;
  2681. lock (_writePacketLockObject) {
  2682. if (_pendingWritePackets.TryGetValue(pointer, out recoveredPacket)) {
  2683. _pendingWritePackets.Remove(pointer);
  2684. _writePacketCache.Add(recoveredPacket);
  2685. }
  2686. #if DEBUG
  2687. else {
  2688. Debug.Assert(false, "Removing a packet from the pending list that was never added to it");
  2689. }
  2690. #endif
  2691. }
  2692. }
  2693. //////////////////////////////////////////////
  2694. // Statistics, Tracing, and related methods //
  2695. //////////////////////////////////////////////
  2696. private void SniReadStatisticsAndTracing() {
  2697. SqlStatistics statistics = Parser.Statistics;
  2698. if (null != statistics) {
  2699. if (statistics.WaitForReply) {
  2700. statistics.SafeIncrement(ref statistics._serverRoundtrips);
  2701. statistics.ReleaseAndUpdateNetworkServerTimer();
  2702. }
  2703. statistics.SafeAdd(ref statistics._bytesReceived, _inBytesRead);
  2704. statistics.SafeIncrement(ref statistics._buffersReceived);
  2705. }
  2706. }
  2707. private void SniWriteStatisticsAndTracing() {
  2708. SqlStatistics statistics = _parser.Statistics;
  2709. if (null != statistics) {
  2710. statistics.SafeIncrement(ref statistics._buffersSent);
  2711. statistics.SafeAdd(ref statistics._bytesSent, _outBytesUsed);
  2712. statistics.RequestNetworkServerTimer();
  2713. }
  2714. if (Bid.AdvancedOn) {
  2715. // If we have tracePassword variables set, we are flushing TDSLogin and so we need to
  2716. // blank out password in buffer. Buffer has already been sent to netlib, so no danger
  2717. // of losing info.
  2718. if (_tracePasswordOffset != 0) {
  2719. for (int i = _tracePasswordOffset; i < _tracePasswordOffset +
  2720. _tracePasswordLength; i++) {
  2721. _outBuff[i] = 0;
  2722. }
  2723. // Reset state.
  2724. _tracePasswordOffset = 0;
  2725. _tracePasswordLength = 0;
  2726. }
  2727. if (_traceChangePasswordOffset != 0) {
  2728. for (int i = _traceChangePasswordOffset; i < _traceChangePasswordOffset +
  2729. _traceChangePasswordLength; i++) {
  2730. _outBuff[i] = 0;
  2731. }
  2732. // Reset state.
  2733. _traceChangePasswordOffset = 0;
  2734. _traceChangePasswordLength = 0;
  2735. }
  2736. Bid.TraceBin("<sc.TdsParser.WritePacket|INFO|ADV> Packet sent", _outBuff, (UInt16)_outBytesUsed);
  2737. }
  2738. }
  2739. [Conditional("DEBUG")]
  2740. void AssertValidState() {
  2741. string assertMessage = null;
  2742. if (_inBytesUsed < 0 || _inBytesRead < 0) {
  2743. assertMessage = string.Format(
  2744. CultureInfo.InvariantCulture,
  2745. "either _inBytesUsed or _inBytesRead is negative: {0}, {1}",
  2746. _inBytesUsed, _inBytesRead);
  2747. }
  2748. else if (_inBytesUsed > _inBytesRead) {
  2749. assertMessage = string.Format(
  2750. CultureInfo.InvariantCulture,
  2751. "_inBytesUsed > _inBytesRead: {0} > {1}",
  2752. _inBytesUsed, _inBytesRead);
  2753. }
  2754. //
  2755. if (assertMessage != null) {
  2756. Debug.Assert(false, "Invalid TDS Parser State: " + assertMessage);
  2757. }
  2758. Debug.Assert(_inBytesPacket >= 0, "Packet must not be negative");
  2759. }
  2760. //////////////////////////////////////////////
  2761. // Errors and Warnings //
  2762. //////////////////////////////////////////////
  2763. /// <summary>
  2764. /// True if there is at least one error or warning (not counting the pre-attention errors\warnings)
  2765. /// </summary>
  2766. internal bool HasErrorOrWarning {
  2767. get {
  2768. return _hasErrorOrWarning;
  2769. }
  2770. }
  2771. /// <summary>
  2772. /// Adds an error to the error collection
  2773. /// </summary>
  2774. /// <param name="error"></param>
  2775. internal void AddError(SqlError error) {
  2776. Debug.Assert(error != null, "Trying to add a null error");
  2777. // Switch to [....] once we see an error
  2778. _syncOverAsync = true;
  2779. lock (_errorAndWarningsLock) {
  2780. _hasErrorOrWarning = true;
  2781. if (_errors == null) {
  2782. _errors = new SqlErrorCollection();
  2783. }
  2784. _errors.Add(error);
  2785. }
  2786. }
  2787. /// <summary>
  2788. /// Gets the number of errors currently in the error collection
  2789. /// </summary>
  2790. internal int ErrorCount {
  2791. get {
  2792. int count = 0;
  2793. lock (_errorAndWarningsLock){
  2794. if (_errors != null) {
  2795. count = _errors.Count;
  2796. }
  2797. }
  2798. return count;
  2799. }
  2800. }
  2801. /// <summary>
  2802. /// Adds an warning to the warning collection
  2803. /// </summary>
  2804. /// <param name="error"></param>
  2805. internal void AddWarning(SqlError error) {
  2806. Debug.Assert(error != null, "Trying to add a null error");
  2807. // Switch to [....] once we see a warning
  2808. _syncOverAsync = true;
  2809. lock (_errorAndWarningsLock){
  2810. _hasErrorOrWarning = true;
  2811. if (_warnings == null) {
  2812. _warnings = new SqlErrorCollection();
  2813. }
  2814. _warnings.Add(error);
  2815. }
  2816. }
  2817. /// <summary>
  2818. /// Gets the number of warnings currently in the warning collection
  2819. /// </summary>
  2820. internal int WarningCount {
  2821. get {
  2822. int count = 0;
  2823. lock (_errorAndWarningsLock){
  2824. if (_warnings != null) {
  2825. count = _warnings.Count;
  2826. }
  2827. }
  2828. return count;
  2829. }
  2830. }
  2831. /// <summary>
  2832. /// Gets the number of errors currently in the pre-attention error collection
  2833. /// </summary>
  2834. internal int PreAttentionErrorCount {
  2835. get {
  2836. int count = 0;
  2837. lock (_errorAndWarningsLock){
  2838. if (_preAttentionErrors != null) {
  2839. count = _preAttentionErrors.Count;
  2840. }
  2841. }
  2842. return count;
  2843. }
  2844. }
  2845. /// <summary>
  2846. /// Gets the number of errors currently in the pre-attention warning collection
  2847. /// </summary>
  2848. internal int PreAttentionWarningCount {
  2849. get {
  2850. int count = 0;
  2851. lock (_errorAndWarningsLock){
  2852. if (_preAttentionWarnings != null) {
  2853. count = _preAttentionWarnings.Count;
  2854. }
  2855. }
  2856. return count;
  2857. }
  2858. }
  2859. /// <summary>
  2860. /// Gets the full list of errors and warnings (including the pre-attention ones), then wipes all error and warning lists
  2861. /// </summary>
  2862. /// <param name="broken">If true, the connection should be broken</param>
  2863. /// <returns>An array containing all of the errors and warnings</returns>
  2864. internal SqlErrorCollection GetFullErrorAndWarningCollection(out bool broken) {
  2865. SqlErrorCollection allErrors = new SqlErrorCollection();
  2866. broken = false;
  2867. lock (_errorAndWarningsLock){
  2868. _hasErrorOrWarning = false;
  2869. // Merge all error lists, then reset them
  2870. AddErrorsToCollection(_errors, ref allErrors, ref broken);
  2871. AddErrorsToCollection(_warnings, ref allErrors, ref broken);
  2872. _errors = null;
  2873. _warnings = null;
  2874. // We also process the pre-attention error lists here since, if we are here and they are populated, then an error occured while sending attention so we should show the errors now (otherwise they'd be lost)
  2875. AddErrorsToCollection(_preAttentionErrors, ref allErrors, ref broken);
  2876. AddErrorsToCollection(_preAttentionWarnings, ref allErrors, ref broken);
  2877. _preAttentionErrors = null;
  2878. _preAttentionWarnings = null;
  2879. }
  2880. return allErrors;
  2881. }
  2882. private void AddErrorsToCollection(SqlErrorCollection inCollection, ref SqlErrorCollection collectionToAddTo, ref bool broken) {
  2883. if (inCollection != null) {
  2884. foreach (SqlError error in inCollection) {
  2885. collectionToAddTo.Add(error);
  2886. broken |= (error.Class >= TdsEnums.FATAL_ERROR_CLASS);
  2887. }
  2888. }
  2889. }
  2890. /// <summary>
  2891. /// Stores away current errors and warnings so that an attention can be processed
  2892. /// </summary>
  2893. internal void StoreErrorAndWarningForAttention() {
  2894. lock (_errorAndWarningsLock){
  2895. Debug.Assert(_preAttentionErrors == null && _preAttentionWarnings == null, "Can't store errors for attention because there are already errors stored");
  2896. _hasErrorOrWarning = false;
  2897. _preAttentionErrors = _errors;
  2898. _preAttentionWarnings = _warnings;
  2899. _errors = null;
  2900. _warnings = null;
  2901. }
  2902. }
  2903. /// <summary>
  2904. /// Restores errors and warnings that were stored in order to process an attention
  2905. /// </summary>
  2906. internal void RestoreErrorAndWarningAfterAttention() {
  2907. lock (_errorAndWarningsLock){
  2908. Debug.Assert(_errors == null && _warnings == null, "Can't restore errors after attention because there are already other errors");
  2909. _hasErrorOrWarning = (((_preAttentionErrors != null) && (_preAttentionErrors.Count > 0)) || ((_preAttentionWarnings != null) && (_preAttentionWarnings.Count > 0)));
  2910. _errors = _preAttentionErrors;
  2911. _warnings = _preAttentionWarnings;
  2912. _preAttentionErrors = null;
  2913. _preAttentionWarnings = null;
  2914. }
  2915. }
  2916. /// <summary>
  2917. /// Checks if an error is stored in _error and, if so, throws an error
  2918. /// </summary>
  2919. internal void CheckThrowSNIException() {
  2920. if (HasErrorOrWarning) {
  2921. ThrowExceptionAndWarning();
  2922. }
  2923. }
  2924. /// <summary>
  2925. /// Debug Only: Ensures that the TdsParserStateObject has no lingering state and can safely be re-used
  2926. /// </summary>
  2927. [Conditional("DEBUG")]
  2928. internal void AssertStateIsClean() {
  2929. // If our TdsParser is closed or broken, then we don't really care about our state
  2930. var parser = _parser;
  2931. if ((parser != null) && (parser.State != TdsParserState.Closed) && (parser.State != TdsParserState.Broken)) {
  2932. // Async reads
  2933. Debug.Assert(_snapshot == null && !_snapshotReplay, "StateObj has leftover snapshot state");
  2934. Debug.Assert(!_asyncReadWithoutSnapshot, "StateObj has AsyncReadWithoutSnapshot still enabled");
  2935. Debug.Assert(_executionContext == null, "StateObj has a stored execution context from an async read");
  2936. // Async writes
  2937. Debug.Assert(_asyncWriteCount == 0, "StateObj still has outstanding async writes");
  2938. Debug.Assert(_delayedWriteAsyncCallbackException == null, "StateObj has an unobserved exceptions from an async write");
  2939. // Attention\Cancellation\Timeouts
  2940. Debug.Assert(!_attentionReceived && !_attentionSent && !_attentionSending, string.Format("StateObj is still dealing with attention: Sent: {0}, Received: {1}, Sending: {2}", _attentionSent, _attentionReceived, _attentionSending));
  2941. Debug.Assert(!_cancelled, "StateObj still has cancellation set");
  2942. Debug.Assert(!_internalTimeout, "StateObj still has internal timeout set");
  2943. // Errors and Warnings
  2944. Debug.Assert(!_hasErrorOrWarning, "StateObj still has stored errors or warnings");
  2945. }
  2946. }
  2947. #if DEBUG
  2948. internal void CompletePendingReadWithSuccess(bool resetForcePendingReadsToWait) {
  2949. var realNetworkPacketTaskSource = _realNetworkPacketTaskSource;
  2950. var networkPacketTaskSource = _networkPacketTaskSource;
  2951. Debug.Assert(_forcePendingReadsToWaitForUser, "Not forcing pends to wait for user - can't force complete");
  2952. Debug.Assert(networkPacketTaskSource != null, "No pending read to complete");
  2953. try {
  2954. if (realNetworkPacketTaskSource != null) {
  2955. // Wait for the real read to complete
  2956. realNetworkPacketTaskSource.Task.Wait();
  2957. }
  2958. }
  2959. finally {
  2960. if (networkPacketTaskSource != null) {
  2961. if (resetForcePendingReadsToWait) {
  2962. _forcePendingReadsToWaitForUser = false;
  2963. }
  2964. networkPacketTaskSource.TrySetResult(null);
  2965. }
  2966. }
  2967. }
  2968. internal void CompletePendingReadWithFailure(int errorCode, bool resetForcePendingReadsToWait) {
  2969. var realNetworkPacketTaskSource = _realNetworkPacketTaskSource;
  2970. var networkPacketTaskSource = _networkPacketTaskSource;
  2971. Debug.Assert(_forcePendingReadsToWaitForUser, "Not forcing pends to wait for user - can't force complete");
  2972. Debug.Assert(networkPacketTaskSource != null, "No pending read to complete");
  2973. try {
  2974. if (realNetworkPacketTaskSource != null) {
  2975. // Wait for the real read to complete
  2976. realNetworkPacketTaskSource.Task.Wait();
  2977. }
  2978. }
  2979. finally {
  2980. if (networkPacketTaskSource != null) {
  2981. if (resetForcePendingReadsToWait) {
  2982. _forcePendingReadsToWaitForUser = false;
  2983. }
  2984. AddError(new SqlError(errorCode, 0x00, TdsEnums.FATAL_ERROR_CLASS, _parser.Server, string.Empty, string.Empty, 0));
  2985. try {
  2986. ThrowExceptionAndWarning();
  2987. }
  2988. catch (Exception ex) {
  2989. networkPacketTaskSource.TrySetException(ex);
  2990. }
  2991. }
  2992. }
  2993. }
  2994. #endif
  2995. internal void CloneCleanupAltMetaDataSetArray()
  2996. {
  2997. if (_snapshot != null) {
  2998. _snapshot.CloneCleanupAltMetaDataSetArray();
  2999. }
  3000. }
  3001. class PacketData {
  3002. public byte[] Buffer;
  3003. public int Read;
  3004. #if DEBUG
  3005. public StackTrace Stack;
  3006. #endif
  3007. }
  3008. class StateSnapshot
  3009. {
  3010. private List<PacketData> _snapshotInBuffs;
  3011. private int _snapshotInBuffCurrent = 0;
  3012. private int _snapshotInBytesUsed = 0;
  3013. private int _snapshotInBytesPacket = 0;
  3014. private bool _snapshotPendingData = false;
  3015. private bool _snapshotErrorTokenReceived = false;
  3016. private bool _snapshotHasOpenResult = false;
  3017. private bool _snapshotReceivedColumnMetadata = false;
  3018. private bool _snapshotAttentionReceived;
  3019. private byte _snapshotMessageStatus;
  3020. private NullBitmap _snapshotNullBitmapInfo;
  3021. private ulong _snapshotLongLen;
  3022. private ulong _snapshotLongLenLeft;
  3023. private _SqlMetaDataSet _snapshotCleanupMetaData;
  3024. private _SqlMetaDataSetCollection _snapshotCleanupAltMetaDataSetArray;
  3025. private readonly TdsParserStateObject _stateObj;
  3026. public StateSnapshot(TdsParserStateObject state) {
  3027. _snapshotInBuffs = new List<PacketData>();
  3028. _stateObj = state;
  3029. }
  3030. #if DEBUG
  3031. private int _rollingPend = 0;
  3032. private int _rollingPendCount = 0;
  3033. internal bool DoPend() {
  3034. if (_failAsyncPends || !_forceAllPends) {
  3035. return false;
  3036. }
  3037. if (_rollingPendCount == _rollingPend) {
  3038. _rollingPend++;
  3039. _rollingPendCount = 0;
  3040. return true;
  3041. }
  3042. _rollingPendCount++;
  3043. return false;
  3044. }
  3045. #endif
  3046. internal void CloneNullBitmapInfo() {
  3047. if (_stateObj._nullBitmapInfo.ReferenceEquals(_snapshotNullBitmapInfo)) {
  3048. _stateObj._nullBitmapInfo = _stateObj._nullBitmapInfo.Clone();
  3049. }
  3050. }
  3051. internal void CloneCleanupAltMetaDataSetArray() {
  3052. if (_stateObj._cleanupAltMetaDataSetArray != null && object.ReferenceEquals(_snapshotCleanupAltMetaDataSetArray, _stateObj._cleanupAltMetaDataSetArray)) {
  3053. _stateObj._cleanupAltMetaDataSetArray = (_SqlMetaDataSetCollection)_stateObj._cleanupAltMetaDataSetArray.Clone();
  3054. }
  3055. }
  3056. internal void PushBuffer(byte[] buffer, int read) {
  3057. Debug.Assert(!_snapshotInBuffs.Any(b => object.ReferenceEquals(b, buffer)));
  3058. PacketData packetData = new PacketData();
  3059. packetData.Buffer = buffer;
  3060. packetData.Read = read;
  3061. #if DEBUG
  3062. packetData.Stack = _stateObj._lastStack;
  3063. #endif
  3064. _snapshotInBuffs.Add(packetData);
  3065. }
  3066. #if DEBUG
  3067. internal void AssertCurrent()
  3068. {
  3069. Debug.Assert(_snapshotInBuffCurrent == _snapshotInBuffs.Count, "Should not be reading new packets when not replaying last packet");
  3070. }
  3071. internal void CheckStack(StackTrace trace)
  3072. {
  3073. PacketData prev = _snapshotInBuffs[_snapshotInBuffCurrent - 1];
  3074. if (prev.Stack == null)
  3075. {
  3076. prev.Stack = trace;
  3077. }
  3078. else
  3079. {
  3080. Debug.Assert(_stateObj._permitReplayStackTraceToDiffer || prev.Stack.ToString() == trace.ToString(), "The stack trace on subsequent replays should be the same");
  3081. }
  3082. }
  3083. #endif
  3084. internal bool Replay() {
  3085. if (_snapshotInBuffCurrent < _snapshotInBuffs.Count) {
  3086. PacketData next = _snapshotInBuffs[_snapshotInBuffCurrent];
  3087. _stateObj._inBuff = next.Buffer;
  3088. _stateObj._inBytesUsed = 0;
  3089. _stateObj._inBytesRead = next.Read;
  3090. _snapshotInBuffCurrent++;
  3091. return true;
  3092. }
  3093. return false;
  3094. }
  3095. internal void Snap()
  3096. {
  3097. _snapshotInBuffs.Clear();
  3098. _snapshotInBuffCurrent = 0;
  3099. _snapshotInBytesUsed = _stateObj._inBytesUsed;
  3100. _snapshotInBytesPacket = _stateObj._inBytesPacket;
  3101. _snapshotPendingData = _stateObj._pendingData;
  3102. _snapshotErrorTokenReceived = _stateObj._errorTokenReceived;
  3103. _snapshotMessageStatus = _stateObj._messageStatus;
  3104. // _nullBitmapInfo must be cloned before it is updated
  3105. _snapshotNullBitmapInfo = _stateObj._nullBitmapInfo;
  3106. _snapshotLongLen = _stateObj._longlen;
  3107. _snapshotLongLenLeft = _stateObj._longlenleft;
  3108. _snapshotCleanupMetaData = _stateObj._cleanupMetaData;
  3109. // _cleanupAltMetaDataSetArray must be cloned bofore it is updated
  3110. _snapshotCleanupAltMetaDataSetArray = _stateObj._cleanupAltMetaDataSetArray;
  3111. _snapshotHasOpenResult = _stateObj._hasOpenResult;
  3112. _snapshotReceivedColumnMetadata = _stateObj._receivedColMetaData;
  3113. _snapshotAttentionReceived = _stateObj._attentionReceived;
  3114. #if DEBUG
  3115. _rollingPend = 0;
  3116. _rollingPendCount = 0;
  3117. _stateObj._lastStack = null;
  3118. Debug.Assert(_stateObj._bTmpRead == 0, "Has partially read data when snapshot taken");
  3119. Debug.Assert(_stateObj._partialHeaderBytesRead == 0, "Has partially read header when shapshot taken");
  3120. #endif
  3121. PushBuffer(_stateObj._inBuff, _stateObj._inBytesRead);
  3122. }
  3123. internal void ResetSnapshotState() {
  3124. // go back to the beginning
  3125. _snapshotInBuffCurrent = 0;
  3126. Replay();
  3127. _stateObj._inBytesUsed = _snapshotInBytesUsed;
  3128. _stateObj._inBytesPacket = _snapshotInBytesPacket;
  3129. _stateObj._pendingData = _snapshotPendingData;
  3130. _stateObj._errorTokenReceived = _snapshotErrorTokenReceived;
  3131. _stateObj._messageStatus = _snapshotMessageStatus;
  3132. _stateObj._nullBitmapInfo = _snapshotNullBitmapInfo;
  3133. _stateObj._cleanupMetaData = _snapshotCleanupMetaData;
  3134. _stateObj._cleanupAltMetaDataSetArray = _snapshotCleanupAltMetaDataSetArray;
  3135. _stateObj._hasOpenResult = _snapshotHasOpenResult;
  3136. _stateObj._receivedColMetaData = _snapshotReceivedColumnMetadata;
  3137. _stateObj._attentionReceived = _snapshotAttentionReceived;
  3138. // Reset partially read state (these only need to be maintained if doing async without snapshot)
  3139. _stateObj._bTmpRead = 0;
  3140. _stateObj._partialHeaderBytesRead = 0;
  3141. // reset plp state
  3142. _stateObj._longlen = _snapshotLongLen;
  3143. _stateObj._longlenleft = _snapshotLongLenLeft;
  3144. _stateObj._snapshotReplay = true;
  3145. _stateObj.AssertValidState();
  3146. }
  3147. internal void PrepareReplay() {
  3148. ResetSnapshotState();
  3149. }
  3150. }
  3151. /*
  3152. // leave this in. comes handy if you have to do Console.WriteLine style debugging ;)
  3153. private void DumpBuffer() {
  3154. Console.WriteLine("dumping buffer");
  3155. Console.WriteLine("_inBytesRead = {0}", _inBytesRead);
  3156. Console.WriteLine("_inBytesUsed = {0}", _inBytesUsed);
  3157. int cc = 0; // character counter
  3158. int i;
  3159. Console.WriteLine("used buffer:");
  3160. for (i=0; i< _inBytesUsed; i++) {
  3161. if (cc==16) {
  3162. Console.WriteLine();
  3163. cc = 0;
  3164. }
  3165. Console.Write("{0,-2:X2} ", _inBuff[i]);
  3166. cc++;
  3167. }
  3168. if (cc>0) {
  3169. Console.WriteLine();
  3170. }
  3171. cc = 0;
  3172. Console.WriteLine("unused buffer:");
  3173. for (i=_inBytesUsed; i<_inBytesRead; i++) {
  3174. if (cc==16) {
  3175. Console.WriteLine();
  3176. cc = 0;
  3177. }
  3178. Console.Write("{0,-2:X2} ", _inBuff[i]);
  3179. cc++;
  3180. }
  3181. if (cc>0) {
  3182. Console.WriteLine();
  3183. }
  3184. }
  3185. */
  3186. }
  3187. }