File: TdsParserSafeHandles.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (263 lines) | stat: -rw-r--r-- 10,346 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
//------------------------------------------------------------------------------
// <copyright file="TdsParserSafeHandles.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------

namespace System.Data.SqlClient {

    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Permissions;
    using System.Threading;
    using System.Runtime.ConstrainedExecution;

    internal sealed class SNILoadHandle : SafeHandle {
        internal static readonly SNILoadHandle SingletonInstance = new SNILoadHandle();

        internal readonly SNINativeMethodWrapper.SqlAsyncCallbackDelegate ReadAsyncCallbackDispatcher  = new SNINativeMethodWrapper.SqlAsyncCallbackDelegate(ReadDispatcher);
        internal readonly SNINativeMethodWrapper.SqlAsyncCallbackDelegate WriteAsyncCallbackDispatcher = new SNINativeMethodWrapper.SqlAsyncCallbackDelegate(WriteDispatcher);

        private readonly UInt32            _sniStatus        = TdsEnums.SNI_UNINITIALIZED;
        private readonly EncryptionOptions _encryptionOption;

        private SNILoadHandle() : base(IntPtr.Zero, true) {
            // SQL BU DT 346588 - from security review - SafeHandle guarantees this is only called once.
            // The reason for the safehandle is guaranteed initialization and termination of SNI to
            // ensure SNI terminates and cleans up properly.
            RuntimeHelpers.PrepareConstrainedRegions();
            try {} finally {
                
                _sniStatus = SNINativeMethodWrapper.SNIInitialize();

                UInt32 value = 0;

                // VSDevDiv 479597: If initialize fails, don't call QueryInfo.
                if (TdsEnums.SNI_SUCCESS == _sniStatus) {
                    // Query OS to find out whether encryption is supported.
                    SNINativeMethodWrapper.SNIQueryInfo(SNINativeMethodWrapper.QTypes.SNI_QUERY_CLIENT_ENCRYPT_POSSIBLE, ref value);
                }

                _encryptionOption = (value == 0) ? EncryptionOptions.NOT_SUP : EncryptionOptions.OFF;

                base.handle = (IntPtr) 1; // Initialize to non-zero dummy variable.
            }
        }

        public override bool IsInvalid {
            get {
                return (IntPtr.Zero == base.handle);
            }
        }

        override protected bool ReleaseHandle() {
            if (base.handle != IntPtr.Zero) {
                if (TdsEnums.SNI_SUCCESS == _sniStatus) {
                    LocalDBAPI.ReleaseDLLHandles();
                    SNINativeMethodWrapper.SNITerminate();
                }
                base.handle = IntPtr.Zero;
            }

            return true;
        }

        public UInt32 SNIStatus {
            get {
                return _sniStatus;
            }
        }

        public EncryptionOptions Options {
            get {
                return _encryptionOption;
            }
        }

        static private void ReadDispatcher(IntPtr key, IntPtr packet, UInt32 error) {
            // This is the app-domain dispatcher for all async read callbacks, It 
            // simply gets the state object from the key that it is passed, and 
            // calls the state object's read callback.
            Debug.Assert(IntPtr.Zero != key, "no key passed to read callback dispatcher?");
            if (IntPtr.Zero != key) {
                // NOTE: we will get a null ref here if we don't get a key that
                //       contains a GCHandle to TDSParserStateObject; that is 
                //       very bad, and we want that to occur so we can catch it.
                GCHandle gcHandle = (GCHandle)key;
                TdsParserStateObject stateObj = (TdsParserStateObject)gcHandle.Target;

                if (null != stateObj) {
                    stateObj.ReadAsyncCallback(IntPtr.Zero, packet, error);
                }
            }
        }

        static private void WriteDispatcher(IntPtr key, IntPtr packet, UInt32 error) {
            // This is the app-domain dispatcher for all async write callbacks, It 
            // simply gets the state object from the key that it is passed, and 
            // calls the state object's write callback.
            Debug.Assert(IntPtr.Zero != key, "no key passed to write callback dispatcher?");
            if (IntPtr.Zero != key) {
                // NOTE: we will get a null ref here if we don't get a key that
                //       contains a GCHandle to TDSParserStateObject; that is 
                //       very bad, and we want that to occur so we can catch it.
                GCHandle gcHandle = (GCHandle)key;
                TdsParserStateObject stateObj = (TdsParserStateObject)gcHandle.Target;

                if (null != stateObj) {
                    stateObj.WriteAsyncCallback(IntPtr.Zero, packet, error);
                }
            }
        }
    }

    internal sealed class SNIHandle : SafeHandle {
        private readonly UInt32 _status = TdsEnums.SNI_UNINITIALIZED;
        private readonly bool   _fSync = false;

        // creates a physical connection
        internal SNIHandle(
            SNINativeMethodWrapper.ConsumerInfo myInfo, 
            string serverName,
            byte[] spnBuffer, 
            bool ignoreSniOpenTimeout, 
            int timeout, 
            out byte[] instanceName, 
            bool flushCache, 
            bool fSync,
            bool fParallel,
            TransparentNetworkResolutionState transparentNetworkResolutionState,
            int totalTimeout)
            : base(IntPtr.Zero, true) {

            RuntimeHelpers.PrepareConstrainedRegions();
            try {} finally {
                _fSync = fSync;
                instanceName = new byte[256]; // Size as specified by netlibs.
                if (ignoreSniOpenTimeout) {
                    // 


                    timeout = Timeout.Infinite; // -1 == native SNIOPEN_TIMEOUT_VALUE / INFINITE
                }

                int transparentNetworkResolutionStateNo = (int)transparentNetworkResolutionState;
                _status = SNINativeMethodWrapper.SNIOpenSyncEx(myInfo, serverName, ref base.handle,
                            spnBuffer, instanceName, flushCache, fSync, timeout, fParallel, transparentNetworkResolutionStateNo, totalTimeout,
                            ADP.IsAzureSqlServerEndpoint(serverName));
            }
        }

        // constructs SNI Handle for MARS session
        internal SNIHandle(SNINativeMethodWrapper.ConsumerInfo myInfo, SNIHandle parent) : base(IntPtr.Zero, true) {
            RuntimeHelpers.PrepareConstrainedRegions();
            try {} finally {          
                _status = SNINativeMethodWrapper.SNIOpenMarsSession(myInfo, parent, ref base.handle, parent._fSync);
            }
        }

        public override bool IsInvalid {
            get {
                return (IntPtr.Zero == base.handle);
            }
        }

        override protected bool ReleaseHandle() {
            // NOTE: The SafeHandle class guarantees this will be called exactly once.
            IntPtr ptr = base.handle;
            base.handle = IntPtr.Zero;
            if (IntPtr.Zero != ptr) {
                if (0 != SNINativeMethodWrapper.SNIClose(ptr)) {
                    return false;   // SNIClose should never fail.
                }
            }
            return true;
        }

        internal UInt32 Status {
            get {
                return _status;
            }
        }
    }

    internal sealed class SNIPacket : SafeHandle {

        internal SNIPacket(SafeHandle sniHandle) : base(IntPtr.Zero, true) {
            SNINativeMethodWrapper.SNIPacketAllocate(sniHandle, SNINativeMethodWrapper.IOType.WRITE, ref base.handle);
            if (IntPtr.Zero == base.handle) {
                throw SQL.SNIPacketAllocationFailure();
            }
        }

        public override bool IsInvalid {
            get {
                return (IntPtr.Zero == base.handle);
            }
        }

        override protected bool ReleaseHandle() {
            // NOTE: The SafeHandle class guarantees this will be called exactly once.
            IntPtr ptr = base.handle;
            base.handle = IntPtr.Zero;
            if (IntPtr.Zero != ptr) {
               SNINativeMethodWrapper.SNIPacketRelease(ptr);
            }
            return true;
        }
    }

    internal sealed class WritePacketCache : IDisposable {
            private bool _disposed;
            private Stack<SNIPacket> _packets;

            public WritePacketCache() {
                _disposed = false;
                _packets = new Stack<SNIPacket>();
            }

            public SNIPacket Take(SNIHandle sniHandle) {
                SNIPacket packet;
                if (_packets.Count > 0) {
                    // Success - reset the packet
                    packet = _packets.Pop();
                    SNINativeMethodWrapper.SNIPacketReset(sniHandle, SNINativeMethodWrapper.IOType.WRITE, packet, SNINativeMethodWrapper.ConsumerNumber.SNI_Consumer_SNI);
                }
                else {
                    // Failed to take a packet - create a new one
                    packet = new SNIPacket(sniHandle);
                }
                return packet;
            }

            public void Add(SNIPacket packet) {
                if (!_disposed) {
                    _packets.Push(packet);
                }
                else {
                    // If we're disposed, then get rid of any packets added to us
                    packet.Dispose();
                }
            }

            public void Clear() {
                while (_packets.Count > 0) {
                    _packets.Pop().Dispose();
                }
            }

            public void Dispose() {
                if (!_disposed) {
                    _disposed = true;
                    Clear();
                }
            }
        }
}