Merge pull request #4709 from myungjoo/fix/4682
[platform/upstream/coreclr.git] / src / debug / shared / dbgtransportsession.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5
6 #include "dbgtransportsession.h"
7
8 #if (!defined(RIGHT_SIDE_COMPILE) && defined(FEATURE_DBGIPC_TRANSPORT_VM)) || (defined(RIGHT_SIDE_COMPILE) && defined(FEATURE_DBGIPC_TRANSPORT_DI))
9
10 // This is the entry type for the IPC event queue owned by the transport.
11 // Each entry contains the multiplexing type of the IPC event plus the 
12 // IPC event itself.
13 struct DbgEventBufferEntry
14 {
15 public:
16     IPCEventType     m_type;
17     BYTE             m_event[CorDBIPC_BUFFER_SIZE];     // buffer for the IPC event
18 };
19
20 //
21 // Provides a robust and secure transport session between a debugger and a debuggee that are potentially on
22 // different machines.
23 //
24 // See DbgTransportSession.h for further detailed comments.
25 //
26
27 #ifndef RIGHT_SIDE_COMPILE
28 // The one and only transport instance for the left side. Allocated and initialized during EE startup (from
29 // Debugger::Startup() in debugger.cpp).
30 DbgTransportSession *g_pDbgTransport = NULL;
31
32 #include "ddmarshalutil.h"
33 #endif // !RIGHT_SIDE_COMPILE
34
35 // No real work done in the constructor. Use Init() instead.
36 DbgTransportSession::DbgTransportSession()
37 {
38     m_ref = 1;
39     m_eState = SS_Closed;
40 }
41
42 DbgTransportSession::~DbgTransportSession()
43 {
44     DbgTransportLog(LC_Proxy, "DbgTransportSession::~DbgTransportSession() called");
45
46     // No other threads are now using session resources. We're free to deallocate them as we wish (if they
47     // were allocated in the first place).
48     if (m_hTransportThread)
49         CloseHandle(m_hTransportThread);
50     if (m_rghEventReadyEvent[IPCET_OldStyle])
51         CloseHandle(m_rghEventReadyEvent[IPCET_OldStyle]);
52     if (m_rghEventReadyEvent[IPCET_DebugEvent])
53         CloseHandle(m_rghEventReadyEvent[IPCET_DebugEvent]);
54     if (m_pEventBuffers)
55         delete [] m_pEventBuffers;
56
57 #ifdef RIGHT_SIDE_COMPILE
58     if (m_hSessionOpenEvent)
59         CloseHandle(m_hSessionOpenEvent);
60
61     if (m_hProcessExited)
62         CloseHandle(m_hProcessExited);
63 #endif // RIGHT_SIDE_COMPILE
64
65     if (m_fInitStateLock)
66         m_sStateLock.Destroy();
67 }
68
69 // Allocates initial resources (including starting the transport thread). The session will start in the
70 // SS_Opening state. That is, the RS will immediately start trying to Connect() a connection while the LS will
71 // perform an accept()/Accept() to wait for a connection request. The RS needs an IP address and port number
72 // to initiate connections. These should be given in host byte order. The LS, on the other hand, requires the
73 // addresses of a couple of runtime data structures to service certain debugger requests that may be delivered
74 // once the session is established.
75 #ifdef RIGHT_SIDE_COMPILE
76 HRESULT DbgTransportSession::Init(DWORD pid, HANDLE hProcessExited)
77 #else // RIGHT_SIDE_COMPILE
78 HRESULT DbgTransportSession::Init(DebuggerIPCControlBlock *pDCB, AppDomainEnumerationIPCBlock *pADB)
79 #endif // RIGHT_SIDE_COMPILE
80 {
81     _ASSERTE(m_eState == SS_Closed);
82
83     // Start with a blank slate so that Shutdown() on a partially initialized instance will only do the
84     // cleanup necessary.
85     memset(this, 0, sizeof(*this));
86
87     // Because of the above memset the embeded classes/structs need to be reinitialized especially
88     // the two way pipe; it expects the in/out handles to be -1 instead of 0.
89     m_ref = 1;
90     m_pipe = TwoWayPipe();
91     m_sStateLock = DbgTransportLock();
92
93     // Initialize all per-session state variables.
94     InitSessionState();
95
96 #ifdef RIGHT_SIDE_COMPILE
97     // The RS randomly allocates a session ID which is sent to the LS in the SessionRequest message. In the
98     // case of network errors during session formation this allows the LS to tell SessionRequest re-sends from
99     // a new request from a different RS.
100     HRESULT hr = CoCreateGuid(&m_sSessionID);
101     if (FAILED(hr))
102         return hr;
103 #endif // RIGHT_SIDE_COMPILE
104
105
106 #ifdef RIGHT_SIDE_COMPILE
107     m_pid = pid;    
108
109     if (!DuplicateHandle(GetCurrentProcess(), 
110                          hProcessExited,
111                          GetCurrentProcess(), 
112                          &m_hProcessExited,
113                          0,      // ignored since we are going to pass DUPLICATE_SAME_ACCESS
114                          FALSE, 
115                          DUPLICATE_SAME_ACCESS))
116     {
117         return HRESULT_FROM_GetLastError();
118     }
119
120     m_fDebuggerAttached = false;
121 #else // RIGHT_SIDE_COMPILE
122     m_pDCB = pDCB;
123     m_pADB = pADB;
124 #endif // RIGHT_SIDE_COMPILE
125
126     m_sStateLock.Init();
127     m_fInitStateLock = true;
128
129 #ifdef RIGHT_SIDE_COMPILE
130     m_hSessionOpenEvent = WszCreateEvent(NULL, TRUE, FALSE, NULL); // Manual reset, not signalled
131     if (m_hSessionOpenEvent == NULL)
132         return E_OUTOFMEMORY;
133 #endif // RIGHT_SIDE_COMPILE
134
135     // Allocate some buffers to receive incoming events. The initial number is chosen arbitrarily, tune as
136     // necessary. This array will need to grow if it fills with unread events (it takes our client a little
137     // time to process each incoming receive). In general, however, one side will not send an unbounded stream
138     // of events to the other without waiting for some kind of response. More usual are small bursts of events
139     // to represent variable sized data (such as a stack trace).
140     m_cEventBuffers = 10;
141     m_pEventBuffers = (DbgEventBufferEntry *)new (nothrow) BYTE[m_cEventBuffers * sizeof(DbgEventBufferEntry)];
142     if (m_pEventBuffers == NULL)
143         return E_OUTOFMEMORY;
144
145     m_rghEventReadyEvent[IPCET_OldStyle] = WszCreateEvent(NULL, FALSE, FALSE, NULL); // Auto reset, not signalled
146     if (m_rghEventReadyEvent[IPCET_OldStyle] == NULL)
147         return E_OUTOFMEMORY;
148
149     m_rghEventReadyEvent[IPCET_DebugEvent] = WszCreateEvent(NULL, FALSE, FALSE, NULL); // Auto reset, not signalled
150     if (m_rghEventReadyEvent[IPCET_DebugEvent] == NULL)
151         return E_OUTOFMEMORY;
152
153     // Start the transport thread which handles forming and re-forming connections, driving the session
154     // state to SS_Open and receiving and initially processing all incoming traffic.
155     AddRef();
156     m_hTransportThread = CreateThread(NULL, 0, TransportWorkerStatic, this, 0, NULL);
157     if (m_hTransportThread == NULL)
158     {
159         Release();
160         return E_OUTOFMEMORY;
161     }
162
163     return S_OK;
164 }
165
166 // Drive the session to the SS_Closed state, which will deallocate all remaining transport resources
167 // (including terminating the transport thread). If this is the RS and the session state is SS_Open at the
168 // time of this call a graceful disconnect will be attempted (which tells the LS to go back to SS_Opening to
169 // look for a new RS rather than interpreting the disconnection as a temporary error and going into
170 // SS_Resync). On either side the session will no longer be functional after this call returns (though Init()
171 // may be called again to start over from the beginning).
172 void DbgTransportSession::Shutdown()
173 {
174     DbgTransportLog(LC_Proxy, "DbgTransportSession::Shutdown() called");
175
176     // The transport thread is allocated last in Init() (since it uses all the other resources that Init()
177     // prepares). Don't do any transport related stuff unless this was allocated (which can happen if
178     // Shutdown() is called after an Init() failure).
179
180     if (m_hTransportThread)
181     {
182         // From SS_Open state try a graceful disconnect.
183         if (m_eState == SS_Open)
184         {
185             DbgTransportLog(LC_Session, "Sending 'SessionClose'");
186             DBG_TRANSPORT_INC_STAT(SentSessionClose);
187             Message sMessage;
188             sMessage.Init(MT_SessionClose);
189             SendMessage(&sMessage, false);
190         }
191
192         // Must take the state lock to make a state transition.
193         {
194             TransportLockHolder sLockHolder(&m_sStateLock);
195
196             // Remember previous state and transition to SS_Closed.
197             SessionState ePreviousState = m_eState;
198             m_eState = SS_Closed;
199
200             if (ePreviousState != SS_Closed)
201             {
202                 m_pipe.Disconnect();
203             }
204
205         } // Leave m_sStateLock
206
207 #ifdef RIGHT_SIDE_COMPILE
208         // Signal the m_hSessionOpenEvent now to quickly error out any callers of WaitForSessionToOpen().
209         SetEvent(m_hSessionOpenEvent);
210 #endif // RIGHT_SIDE_COMPILE
211     }
212
213     // The transport instance is no longer valid
214     Release();
215 }
216
217 #ifndef RIGHT_SIDE_COMPILE
218
219 // Cleans up the named pipe connection so no tmp files are left behind. Does only
220 // the minimum and must be safe to call at any time. Called during PAL ExitProcess,
221 // TerminateProcess and for unhandled native exceptions and asserts.
222 void DbgTransportSession::AbortConnection()
223 {
224     m_pipe.Disconnect();
225 }
226
227 // API used only by the LS to drive the transport into a state where it won't accept connections. This is used
228 // when no proxy is detected at startup but it's too late to shutdown all of the debugging system easily. It's
229 // mainly paranoia to increase the protection of your system when the proxy isn't started.
230 void DbgTransportSession::Neuter()
231 {
232     // Simply set the session state to SS_Closed. The transport thread will switch itself off if it ever gets
233     // a connection but the rest of the transport resources remain valid (so the debugger helper thread won't
234     // AV on a deallocated handle, which might happen if we simply called Shutdown()).
235     m_eState = SS_Closed;
236 }
237
238 #else // RIGHT_SIDE_COMPILE
239
240 // Used by debugger side (RS) to cleanup the target (LS) named pipes 
241 // and semaphores when the debugger detects the debuggee process  exited.
242 void DbgTransportSession::CleanupTargetProcess()
243 {
244     m_pipe.CleanupTargetProcess();
245 }
246
247 // On the RS it may be useful to wait and see if the session can reach the SS_Open state. If the target
248 // runtime has terminated for some reason then we'll never reach the open state. So the method below gives the
249 // RS a way to try and establish a connection for a reasonable amount of time and to time out otherwise. They
250 // could then call Shutdown on the session and report an error back to the rest of the debugger. The method
251 // returns true if the session opened within the time given (in milliseconds) and false otherwise.
252 bool DbgTransportSession::WaitForSessionToOpen(DWORD dwTimeout)
253 {
254     DWORD dwRet = WaitForSingleObject(m_hSessionOpenEvent, dwTimeout);
255     if (m_eState == SS_Closed)
256         return false;
257
258     if (dwRet == WAIT_TIMEOUT)
259         DbgTransportLog(LC_Proxy, "DbgTransportSession::WaitForSessionToOpen(%u) timed out", dwTimeout);
260
261     return dwRet == WAIT_OBJECT_0;
262 }
263
264 //---------------------------------------------------------------------------------------
265 //
266 // A valid ticket is returned if no other client is currently acting as the debugger.
267 // If the caller passes in a valid ticket, this function will return true without invalidating the ticket.
268 //
269 // Arguments:
270 //    pTicket - out parameter; set to a valid ticket if the client has successfully registered as the debugger
271 //
272 // Return Value:
273 //    Return true if the client has successfully registered as the debugger.
274 //
275
276 bool DbgTransportSession::UseAsDebugger(DebugTicket * pTicket)
277 {
278     TransportLockHolder sLockHolder(&m_sStateLock);
279     if (m_fDebuggerAttached)
280     {
281         if (pTicket->IsValid())
282         {
283             // The client already holds a valid ticket.
284             return true;
285         }
286         else
287         {
288             // Another client of this session has already indicated that it's using this session to debug.
289             _ASSERTE(!pTicket->IsValid());
290             return false;
291         }
292     }
293     else
294     {
295         m_fDebuggerAttached = true;
296         pTicket->SetValid();
297         return true;
298     }
299 }
300
301 //---------------------------------------------------------------------------------------
302 //
303 // A valid ticket is required in order for this function to succeed.  After this function succeeds,
304 // another client can request to be the debugger.
305 //
306 // Arguments:
307 //    pTicket - the client's ticket; must be valid for this function to succeed
308 //
309 // Return Value:
310 //    Return true if the client has successfully unregistered as the debugger.
311 //    Return false if no client is currently acting as the debugger or if the client's ticket is invalid.
312 //
313
314 bool DbgTransportSession::StopUsingAsDebugger(DebugTicket * pTicket)
315 {
316     TransportLockHolder sLockHolder(&m_sStateLock);
317     if (m_fDebuggerAttached && pTicket->IsValid())
318     {
319         // The caller is indeed the owner of the debug ticket.
320         m_fDebuggerAttached = false;
321         pTicket->SetInvalid();
322         return true;
323     }
324     else
325     {
326         return false;
327     }
328 }
329 #endif // RIGHT_SIDE_COMPILE
330
331 // Sends a pre-initialized event to the other side.
332 HRESULT DbgTransportSession::SendEvent(DebuggerIPCEvent *pEvent)
333 {
334     DbgTransportLog(LC_Events, "Sending '%s'", IPCENames::GetName(pEvent->type));
335     DBG_TRANSPORT_INC_STAT(SentEvent);
336
337     return SendEventWorker(pEvent, IPCET_OldStyle);
338 }
339
340 // Sends a pre-initialized event to the other side, but pretend that this is coming from the native pipeline.
341 // See code:IPCEventType for more information.
342 HRESULT DbgTransportSession::SendDebugEvent(DebuggerIPCEvent * pEvent)
343 {
344     DbgTransportLog(LC_Events, "Sending '%s' as DEBUG_EVENT", IPCENames::GetName(pEvent->type));
345     DBG_TRANSPORT_INC_STAT(SentEvent);
346
347     return SendEventWorker(pEvent, IPCET_DebugEvent);
348 }
349
350 // Retrieves the auto-reset handle which is signalled by the session each time a new event is received from
351 // the other side.
352 HANDLE DbgTransportSession::GetIPCEventReadyEvent()
353 {
354     return m_rghEventReadyEvent[IPCET_OldStyle];
355 }
356
357 // Retrieves the auto-reset handle which is signalled by the session each time a new event (disguised as a 
358 // debug event) is received from the other side.
359 HANDLE DbgTransportSession::GetDebugEventReadyEvent()
360 {
361     return m_rghEventReadyEvent[IPCET_DebugEvent];
362 }
363
364 // Copies the last event received from the other side into the provided buffer. This should only be called
365 // (once) after the event returned from GetIPCEEventReadyEvent()/GetDebugEventReadyEvent() has been signalled.
366 void DbgTransportSession::GetNextEvent(DebuggerIPCEvent *pEvent, DWORD cbEvent)
367 {
368     _ASSERTE(cbEvent <= CorDBIPC_BUFFER_SIZE);
369
370     // Must acquire the state lock to synchronize us wrt to the transport thread (clients already guarantee
371     // they serialize calls to this and waiting on m_rghEventReadyEvent).
372     TransportLockHolder sLockHolder(&m_sStateLock);
373
374     // There must be at least one valid event waiting (this call does not block).
375     _ASSERTE(m_cValidEventBuffers);
376
377     // Copy the first valid event into the client's buffer.
378     memcpy(pEvent, &m_pEventBuffers[m_idxEventBufferHead].m_event, cbEvent);
379
380     // Move the index of the head of the valid list forward (which may in fact move it back to the start of
381     // the array since the list is circular). This reduces the number of valid entries by one. Note that these
382     // two adjustments do not affect the tail of the list in any way. In the limit case the head will end up
383     // pointing to the same event as the tail (and m_cValidEventBuffers will be zero).
384     m_idxEventBufferHead = (m_idxEventBufferHead + 1) % m_cEventBuffers;
385     m_cValidEventBuffers--;
386     _ASSERTE(((m_idxEventBufferHead + m_cValidEventBuffers) % m_cEventBuffers) == m_idxEventBufferTail);
387
388     // If there's at least one more valid event we can signal event ready now.
389     if (m_cValidEventBuffers)
390     {
391         SetEvent(m_rghEventReadyEvent[m_pEventBuffers[m_idxEventBufferHead].m_type]);
392     }
393 }
394
395
396
397 void MarshalDCBTransportToDCB(DebuggerIPCControlBlockTransport* pIn, DebuggerIPCControlBlock* pOut)
398 {
399     pOut->m_DCBSize =                         pIn->m_DCBSize;
400     pOut->m_verMajor =                        pIn->m_verMajor;
401     pOut->m_verMinor =                        pIn->m_verMinor;
402     pOut->m_checkedBuild =                    pIn->m_checkedBuild;
403     pOut->m_bHostingInFiber =                 pIn->m_bHostingInFiber;
404     pOut->padding2 =                          pIn->padding2;
405     pOut->padding3 =                          pIn->padding3;
406
407     pOut->m_leftSideProtocolCurrent =         pIn->m_leftSideProtocolCurrent;
408     pOut->m_leftSideProtocolMinSupported =    pIn->m_leftSideProtocolMinSupported;
409
410     pOut->m_rightSideProtocolCurrent =        pIn->m_rightSideProtocolCurrent;
411     pOut->m_rightSideProtocolMinSupported =   pIn->m_rightSideProtocolMinSupported;
412
413     pOut->m_errorHR =                         pIn->m_errorHR;
414     pOut->m_errorCode =                       pIn->m_errorCode;
415
416 #if defined(DBG_TARGET_WIN64)
417     pOut->padding4 =                          pIn->padding4;
418 #endif // DBG_TARGET_WIN64
419
420
421     // 
422     //pOut->m_rightSideEventAvailable
423     //pOut->m_rightSideEventRead
424     //pOut->m_paddingObsoleteLSEA
425     //pOut->m_paddingObsoleteLSER
426     //pOut->m_rightSideProcessHandle
427     //pOut->m_leftSideUnmanagedWaitEvent
428     
429     pOut->m_realHelperThreadId =             pIn->m_realHelperThreadId;
430     pOut->m_helperThreadId =                 pIn->m_helperThreadId;
431     pOut->m_temporaryHelperThreadId =        pIn->m_temporaryHelperThreadId;
432     pOut->m_CanaryThreadId =                 pIn->m_CanaryThreadId;
433     pOut->m_pRuntimeOffsets =                pIn->m_pRuntimeOffsets;
434     pOut->m_helperThreadStartAddr =          pIn->m_helperThreadStartAddr;
435     pOut->m_helperRemoteStartAddr =          pIn->m_helperRemoteStartAddr;
436     pOut->m_specialThreadList =              pIn->m_specialThreadList;
437
438     //
439     //pOut->m_receiveBuffer
440     //pOut->m_sendBuffer
441
442     pOut->m_specialThreadListLength =        pIn->m_specialThreadListLength;
443     pOut->m_shutdownBegun =                  pIn->m_shutdownBegun;
444     pOut->m_rightSideIsWin32Debugger =       pIn->m_rightSideIsWin32Debugger;
445     pOut->m_specialThreadListDirty =         pIn->m_specialThreadListDirty;
446
447     pOut->m_rightSideShouldCreateHelperThread = pIn->m_rightSideShouldCreateHelperThread;
448
449 }
450
451 void MarshalDCBToDCBTransport(DebuggerIPCControlBlock* pIn, DebuggerIPCControlBlockTransport* pOut)
452 {
453     pOut->m_DCBSize =                         pIn->m_DCBSize;
454     pOut->m_verMajor =                        pIn->m_verMajor;
455     pOut->m_verMinor =                        pIn->m_verMinor;
456     pOut->m_checkedBuild =                    pIn->m_checkedBuild;
457     pOut->m_bHostingInFiber =                 pIn->m_bHostingInFiber;
458     pOut->padding2 =                          pIn->padding2;
459     pOut->padding3 =                          pIn->padding3;
460
461     pOut->m_leftSideProtocolCurrent =         pIn->m_leftSideProtocolCurrent;
462     pOut->m_leftSideProtocolMinSupported =    pIn->m_leftSideProtocolMinSupported;
463
464     pOut->m_rightSideProtocolCurrent =        pIn->m_rightSideProtocolCurrent;
465     pOut->m_rightSideProtocolMinSupported =   pIn->m_rightSideProtocolMinSupported;
466
467     pOut->m_errorHR =                         pIn->m_errorHR;
468     pOut->m_errorCode =                       pIn->m_errorCode;
469
470 #if defined(DBG_TARGET_WIN64)
471     pOut->padding4 =                          pIn->padding4;
472 #endif // DBG_TARGET_WIN64
473     
474     pOut->m_realHelperThreadId =             pIn->m_realHelperThreadId;
475     pOut->m_helperThreadId =                 pIn->m_helperThreadId;
476     pOut->m_temporaryHelperThreadId =        pIn->m_temporaryHelperThreadId;
477     pOut->m_CanaryThreadId =                 pIn->m_CanaryThreadId;
478     pOut->m_pRuntimeOffsets =                pIn->m_pRuntimeOffsets;
479     pOut->m_helperThreadStartAddr =          pIn->m_helperThreadStartAddr;
480     pOut->m_helperRemoteStartAddr =          pIn->m_helperRemoteStartAddr;
481     pOut->m_specialThreadList =              pIn->m_specialThreadList;
482
483     pOut->m_specialThreadListLength =        pIn->m_specialThreadListLength;
484     pOut->m_shutdownBegun =                  pIn->m_shutdownBegun;
485     pOut->m_rightSideIsWin32Debugger =       pIn->m_rightSideIsWin32Debugger;
486     pOut->m_specialThreadListDirty =         pIn->m_specialThreadListDirty;
487
488     pOut->m_rightSideShouldCreateHelperThread = pIn->m_rightSideShouldCreateHelperThread;
489 }
490
491
492
493 #ifdef RIGHT_SIDE_COMPILE
494 // Read and write memory on the LS from the RS.
495 HRESULT DbgTransportSession::ReadMemory(PBYTE pbRemoteAddress, PBYTE pbBuffer, SIZE_T cbBuffer)
496 {
497     DbgTransportLog(LC_Requests, "Sending 'ReadMemory(0x%08X, %u)'", pbRemoteAddress, cbBuffer);
498     DBG_TRANSPORT_INC_STAT(SentReadMemory);
499
500     Message sMessage;
501     sMessage.Init(MT_ReadMemory, NULL, 0, pbBuffer, (DWORD)cbBuffer);
502     sMessage.m_sHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = pbRemoteAddress;
503     sMessage.m_sHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = (DWORD)cbBuffer;
504
505     HRESULT hr = SendRequestMessageAndWait(&sMessage);
506     if (FAILED(hr))
507         return hr;
508
509     // If we reached here the send was successful but the actual memory operation may not have been (due to
510     // unmapped memory or page protections etc.). So the final result comes back to us in the reply.
511     return sMessage.m_sHeader.TypeSpecificData.MemoryAccess.m_hrResult;
512 }
513
514 HRESULT DbgTransportSession::WriteMemory(PBYTE pbRemoteAddress, PBYTE pbBuffer, SIZE_T cbBuffer)
515 {
516     DbgTransportLog(LC_Requests, "Sending 'WriteMemory(0x%08X, %u)'", pbRemoteAddress, cbBuffer);
517     DBG_TRANSPORT_INC_STAT(SentWriteMemory);
518
519     Message sMessage;
520     sMessage.Init(MT_WriteMemory, pbBuffer, (DWORD)cbBuffer);
521     sMessage.m_sHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = pbRemoteAddress;
522     sMessage.m_sHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = (DWORD)cbBuffer;
523
524     HRESULT hr = SendRequestMessageAndWait(&sMessage);
525     if (FAILED(hr))
526         return hr;
527
528     // If we reached here the send was successful but the actual memory operation may not have been (due to
529     // unmapped memory or page protections etc.). So the final result comes back to us in the reply.
530     return sMessage.m_sHeader.TypeSpecificData.MemoryAccess.m_hrResult;
531 }
532
533 HRESULT DbgTransportSession::VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
534 {
535     DbgTransportLog(LC_Requests, "Sending 'VirtualUnwind'");
536     DBG_TRANSPORT_INC_STAT(SentVirtualUnwind);
537
538     Message sMessage;
539     sMessage.Init(MT_VirtualUnwind, context, contextSize, context, contextSize);
540     return SendRequestMessageAndWait(&sMessage);
541 }
542
543 // Read and write the debugger control block on the LS from the RS.
544 HRESULT DbgTransportSession::GetDCB(DebuggerIPCControlBlock *pDCB)
545 {
546     DbgTransportLog(LC_Requests, "Sending 'GetDCB'");
547     DBG_TRANSPORT_INC_STAT(SentGetDCB);
548
549     Message sMessage;
550     DebuggerIPCControlBlockTransport dcbt;
551     sMessage.Init(MT_GetDCB, NULL, 0, (PBYTE)&dcbt, sizeof(DebuggerIPCControlBlockTransport));
552     HRESULT ret = SendRequestMessageAndWait(&sMessage);
553
554     MarshalDCBTransportToDCB(&dcbt, pDCB);
555     return ret;
556 }
557
558 HRESULT DbgTransportSession::SetDCB(DebuggerIPCControlBlock *pDCB)
559 {
560     DbgTransportLog(LC_Requests, "Sending 'SetDCB'");
561     DBG_TRANSPORT_INC_STAT(SentSetDCB);
562
563     DebuggerIPCControlBlockTransport dcbt;
564     MarshalDCBToDCBTransport(pDCB, &dcbt);
565
566     Message sMessage;
567     sMessage.Init(MT_SetDCB, (PBYTE)&dcbt, sizeof(DebuggerIPCControlBlockTransport));
568     return SendRequestMessageAndWait(&sMessage);
569
570 }
571
572 // Read the AppDomain control block on the LS from the RS.
573 HRESULT DbgTransportSession::GetAppDomainCB(AppDomainEnumerationIPCBlock *pADB)
574 {
575     DbgTransportLog(LC_Requests, "Sending 'GetAppDomainCB'");
576     DBG_TRANSPORT_INC_STAT(SentGetAppDomainCB);
577
578     Message sMessage;
579     sMessage.Init(MT_GetAppDomainCB, NULL, 0, (PBYTE)pADB, sizeof(AppDomainEnumerationIPCBlock));
580     return SendRequestMessageAndWait(&sMessage);
581 }
582
583 #endif // RIGHT_SIDE_COMPILE
584
585 // Worker function for code:DbgTransportSession::SendEvent and code:DbgTransportSession::SendDebugEvent.
586 HRESULT DbgTransportSession::SendEventWorker(DebuggerIPCEvent * pEvent, IPCEventType type)
587 {
588     DWORD cbEvent = GetEventSize(pEvent);
589     _ASSERTE(cbEvent <= CorDBIPC_BUFFER_SIZE);
590
591     Message sMessage;
592     sMessage.Init(MT_Event, (PBYTE)pEvent, cbEvent);
593
594     // Store the event type in the header as well, it's sometimes useful for debugging.
595     sMessage.m_sHeader.TypeSpecificData.Event.m_eIPCEventType = type;
596     sMessage.m_sHeader.TypeSpecificData.Event.m_eType = pEvent->type;
597
598     return SendMessage(&sMessage, false);
599 }
600
601 // Sends a pre-formatted message (including the data block, if any). The fWaitsForReply indicates whether the
602 // caller is going to block until some sort of reply message is received (for instance an event that must be
603 // ack'd or a request such as MT_GetDCB that needs a reply). SendMessage() uses this to determine whether it
604 // needs to buffer the message before placing it on the send queue (since it may need to resend the message
605 // after a transitory network failure).
606 HRESULT DbgTransportSession::SendMessage(Message *pMessage, bool fWaitsForReply)
607 {
608     // Serialize the whole operation under the state lock. In particular we need to make allocating the
609     // message ID atomic wrt placing the message on the connection (to ensure our IDs are seen in order by the
610     // other side). We also need to hold the lock while manipulating the send queue (to prevent corruption)
611     // and while determining whether to send immediately or not depending on the session state (to avoid
612     // posting a send on a closed and possibly recycled socket).
613     {
614         TransportLockHolder sLockHolder(&m_sStateLock);
615
616         // Perform any last updates to the header or data block here since we might be about to encrypt them.
617
618         // Give this message a unique ID (useful both to track which messages need to be resent on a network
619         // failure and to match replies to the original message).
620         pMessage->m_sHeader.m_dwId = m_dwNextMessageId++;
621
622         // Use this message send to piggyback an acknowledgement of the last message we processed from the
623         // other side (this will allow the other side to discard one or more buffered messages from its send
624         // queue).
625         pMessage->m_sHeader.m_dwLastSeenId = m_dwLastMessageIdSeen;
626
627         // If the caller isn't waiting around for a reply we must make a copy of the message to place on the
628         // send queue.
629         pMessage->m_pOrigMessage = pMessage;
630         Message *pMessageCopy = NULL;
631         PBYTE pDataBlockCopy = NULL;
632         if (!fWaitsForReply)
633         {
634             // Allocate a new message (includes an embedded message header).
635             pMessageCopy = new (nothrow) Message();
636             if (pMessageCopy == NULL)
637                 return E_OUTOFMEMORY;
638
639             // Allocate a new data block if one is being used.
640             if (pMessage->m_pbDataBlock)
641             {
642                 pDataBlockCopy = new (nothrow) BYTE[pMessage->m_cbDataBlock];
643                 if (pDataBlockCopy == NULL)
644                 {
645                     delete pMessageCopy;
646                     return E_OUTOFMEMORY;
647                 }
648             }
649  
650             // Copy the message descriptor over.
651             memcpy(pMessageCopy, pMessage, sizeof(Message));
652
653             // And the data block if applicable.
654             if (pDataBlockCopy)
655                 memcpy(pDataBlockCopy, pMessage->m_pbDataBlock, pMessage->m_cbDataBlock);
656
657             // The message copy still points to the wrong data block (if there is one).
658             pMessageCopy->m_pbDataBlock = pDataBlockCopy;
659
660             // Point the copy back to the original message.
661             pMessageCopy->m_pOrigMessage = pMessage;
662
663             // From now on we'll use the copy.
664             pMessage = pMessageCopy;
665         }
666
667         // Check the session state.
668         if (m_eState == SS_Closed)
669         {
670             // SS_Closed is bad news, we'll never recover from that so error the send immediately.
671             if (pMessageCopy)
672                 delete pMessageCopy;
673             if (pDataBlockCopy)
674                 delete [] pDataBlockCopy;
675
676             return E_ABORT;
677         }
678
679         // Don't queue session management messages. We always recreate these if we need to re-send them.
680         if (pMessage->m_sHeader.m_eType > MT_SessionClose)
681         {
682             // Regardless of session state we always queue the message for at least as long as it takes us to
683             // be sure the other side has received the message.
684             if (m_pSendQueueLast == NULL)
685             {
686                 // Queue is currently empty.
687                 m_pSendQueueFirst = pMessage;
688                 m_pSendQueueLast = pMessage;
689                 pMessage->m_pNext = NULL;
690             }
691             else
692             {
693                 // Place on end of queue.
694                 m_pSendQueueLast->m_pNext = pMessage;
695                 m_pSendQueueLast = pMessage;
696                 pMessage->m_pNext = NULL;
697             }
698         }
699
700         // If the state is SS_Open we can send the message now.
701         if (m_eState == SS_Open)
702         {
703             // Send the message header block followed by the data block if it's provided. Any network error will
704             // be reported internally by SendBlock and result in a transition to the SS_Resync_NC state (and an
705             // eventual resend of the data).
706             if (SendBlock((PBYTE)&pMessage->m_sHeader, sizeof(MessageHeader)) && pMessage->m_pbDataBlock)
707                 SendBlock(pMessage->m_pbDataBlock, pMessage->m_cbDataBlock);
708         }
709
710         // If the state wasn't open there's nothing more to be done. The state will eventually transition to
711         // either SS_Open (in which case the transport thread will send all pending messages for us at the
712         // transition point) or SS_Closed (where the transport thread will drain the queue and discard each
713         // message, setting m_fAborted if necessary).
714
715     } // Leave m_sStateLock
716
717     return S_OK;
718 }
719
720 // Helper method for sending messages requiring a reply (such as MT_GetDCB) and waiting on the result.
721 HRESULT DbgTransportSession::SendRequestMessageAndWait(Message *pMessage)
722 {
723     // Allocate event to wait for reply on.
724     pMessage->m_hReplyEvent = WszCreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, not signalled
725     if (pMessage->m_hReplyEvent == NULL)
726         return E_OUTOFMEMORY;
727
728     // Duplicate the handle to the event.  It's necessary to have two handles to the same event because 
729     // both this thread and the message pumping thread may be trying to access the handle at the same
730     // time (e.g. closing the handle).  So we make a duplicate handle.  This thread is responsible for
731     // closing hReplyEvent (the local variable) whereas the message pumping thread is responsible for
732     // closing the handle on the message.
733     HANDLE hReplyEvent = NULL;
734     if (!DuplicateHandle(GetCurrentProcess(), 
735                          pMessage->m_hReplyEvent, 
736                          GetCurrentProcess(), 
737                          &hReplyEvent, 
738                          0,      // ignored since we are going to pass DUPLICATE_SAME_ACCESS
739                          FALSE, 
740                          DUPLICATE_SAME_ACCESS))
741     {
742         return HRESULT_FROM_GetLastError();
743     }
744
745     // Send the request.
746     HRESULT hr = SendMessage(pMessage, true);
747     if (FAILED(hr))
748     {
749         // In this case, we need to close both handles since the message is never put into the send queue.
750         // This thread is the only one who has access to the message.
751         CloseHandle(pMessage->m_hReplyEvent);
752         CloseHandle(hReplyEvent);
753         return hr;
754     }
755
756     // At this point, the message pumping thread may receive the reply any time.  It may even receive the 
757     // reply message even before we wait on the event.  Keep this in mind.
758
759     // Wait for a reply (by the time this event is signalled the message header will have been overwritten by
760     // the reply and any output buffer provided will have been filled in).
761 #if defined(RIGHT_SIDE_COMPILE)
762     HANDLE rgEvents[] = { hReplyEvent, m_hProcessExited };
763 #else  // !RIGHT_SIDE_COMPILE
764     HANDLE rgEvents[] = { hReplyEvent };
765 #endif // RIGHT_SIDE_COMPILE
766
767     DWORD dwResult = WaitForMultipleObjectsEx(sizeof(rgEvents)/sizeof(rgEvents[0]), rgEvents, FALSE, INFINITE, FALSE);
768     
769     if (dwResult == WAIT_OBJECT_0)
770     {
771         // This is the normal case.  The message pumping thread receives a reply from the debuggee process.  
772         // It signals the event to wake up this thread.
773         CloseHandle(hReplyEvent);
774
775         // Check whether the session aborted us due to a Shutdown().
776         if (pMessage->m_fAborted)
777             return E_ABORT;
778     }
779 #if defined(RIGHT_SIDE_COMPILE)
780     else if (dwResult == (WAIT_OBJECT_0 + 1))
781     {
782         // This is the complicated case.  This thread wakes up because the debuggee process is terminated.
783         // At the same time, the message pumping thread may be in the process of handling the reply message.
784         // We need to be careful here because there is a race condition.
785
786         // Remove the original message from the send queue.  This is because in the case of a blocking message,
787         // the message can be allocated on the stack.  Thus, the message becomes invalid when we return from 
788         // this function.  The message pumping thread may have beaten this thread to it.  That's ok since
789         // RemoveMessageFromSendQueue() takes the state lock.
790         Message * pOriginalMessage = RemoveMessageFromSendQueue(pMessage->m_sHeader.m_dwId);
791         _ASSERTE((pOriginalMessage == NULL) || (pOriginalMessage == pMessage));
792
793         // If the message pumping thread has beaten this thread to removing the original message, then this
794         // thread must wait until the message pumping thread is done with the message before returning.
795         // Otherwise, the message may become invalid when the message pumping thread is accessing it.
796         // Fortunately, in this case, we know the message pumping thread is going to signal the event.
797         if (pOriginalMessage == NULL)
798         {
799             WaitForSingleObject(hReplyEvent, INFINITE);
800         }
801
802         CloseHandle(hReplyEvent);
803         return CORDBG_E_PROCESS_TERMINATED;
804     }
805 #endif // RIGHT_SIDE_COMPILE
806     else
807     {
808         // Should never get here.
809         CloseHandle(hReplyEvent);
810         UNREACHABLE();
811     }
812
813     return S_OK;
814 }
815
816 // Sends a single contiguous buffer of host memory over the connection. The caller is responsible for holding
817 // the state lock and ensuring the session state is SS_Open. Returns false if the send failed (the error will
818 // have already caused the recovery logic to kick in, so handling it is not required, the boolean is just
819 // returned so that any further blocks in the message are not sent).
820 bool DbgTransportSession::SendBlock(PBYTE pbBuffer, DWORD cbBuffer)
821 {
822     _ASSERTE(m_eState == SS_Opening || m_eState == SS_Resync || m_eState == SS_Open);
823     _ASSERTE(m_pipe.GetState() == TwoWayPipe::ServerConnected || m_pipe.GetState() == TwoWayPipe::ClientConnected);
824     _ASSERTE(cbBuffer > 0);
825
826     DBG_TRANSPORT_INC_STAT(SentBlocks);
827     DBG_TRANSPORT_ADD_STAT(SentBytes, cbBuffer);
828
829     //DbgTransportLog(LC_Proxy, "SendBlock(%08X, %u)", pbBuffer, cbBuffer);
830     bool fSuccess;
831     if (DBG_TRANSPORT_SHOULD_INJECT_FAULT(Send))
832         fSuccess = false;
833     else
834         fSuccess = (m_pipe.Write(pbBuffer, cbBuffer) == cbBuffer);
835
836     if (!fSuccess)
837     {
838         DbgTransportLog(LC_NetErrors, "Network error on Send()");
839         DBG_TRANSPORT_INC_STAT(SendErrors);
840         HandleNetworkError(true);
841         return false;
842     }
843
844     return true;
845 }
846
847 // Receives a single contiguous buffer of host memory over the connection. No state lock needs to be held
848 // (receives are serialized by the fact they're only performed on the transport thread). Returns false if a
849 // network error is encountered (which will automatically transition the session into the correct retry
850 // state).
851 bool DbgTransportSession::ReceiveBlock(PBYTE pbBuffer, DWORD cbBuffer)
852 {
853     _ASSERTE(m_pipe.GetState() == TwoWayPipe::ServerConnected || m_pipe.GetState() == TwoWayPipe::ClientConnected);
854     _ASSERTE(cbBuffer > 0);
855
856     DBG_TRANSPORT_INC_STAT(ReceivedBlocks);
857     DBG_TRANSPORT_ADD_STAT(ReceivedBytes, cbBuffer);
858
859     //DbgTransportLog(LC_Proxy, "ReceiveBlock(%08X, %u)", pbBuffer, cbBuffer);
860
861     bool fSuccess;
862     if (DBG_TRANSPORT_SHOULD_INJECT_FAULT(Receive))
863         fSuccess = false;
864     else
865         fSuccess = (m_pipe.Read(pbBuffer, cbBuffer) == cbBuffer);
866
867     if (!fSuccess)
868     {
869         DbgTransportLog(LC_NetErrors, "Network error on Receive()");
870         DBG_TRANSPORT_INC_STAT(ReceiveErrors);
871         HandleNetworkError(false);
872         return false;
873     }
874
875     return true;
876 }
877
878 // Called upon encountering a network error (e.g. an error from Send() or Receive()). This handles pushing the
879 // session state into SS_Resync_NC or SS_Opening_NC in order to start the recovery process.
880 void DbgTransportSession::HandleNetworkError(bool fCallerHoldsStateLock)
881 {
882     _ASSERTE(m_eState == SS_Open || m_eState == SS_Opening || m_eState == SS_Resync || !fCallerHoldsStateLock);
883
884     // Check the easy cases first which don't require us to take the lock (because we don't transition the
885     // state). These are the SS_Closed state (a network error doesn't matter when we're closing down the
886     // session anyway) and the SS_*_NC states (which indicate someone else beat us to it, closed the
887     // connection and has started recovery).
888     if (m_eState == SS_Closed ||
889         m_eState == SS_Opening_NC ||
890         m_eState == SS_Resync_NC)
891         return;
892
893     // We need the state lock to perform a state transition.
894     if (!fCallerHoldsStateLock)
895         m_sStateLock.Enter();
896
897     switch (m_eState)
898     {
899     case SS_Closed:
900     case SS_Opening_NC:
901     case SS_Resync_NC:
902         // Still need to cope with the no-op states handled above since we could have transitioned into them
903         // before we took the lock.
904         break;
905
906     case SS_Opening:
907         // All work to transition SS_Opening to SS_Open is performed by the transport thread, so we know we're
908         // on that thread. Consequently it's just enough to set the state to SS_Opening_NC and the thread will
909         // notice the change when the SendMessage() or ReceiveBlock() call completes.
910         m_eState = SS_Opening_NC;
911         break;
912
913     case SS_Resync:
914         // Likewise, all the work to transition SS_Resync to SS_Open is performed by the transport thread, so
915         // we know we're on that thread.
916         m_eState = SS_Resync_NC;
917         break;
918
919     case SS_Open:
920         // The state change to SS_Resync_NC will prompt the transport thread (which might be this thread) that
921         // it should discard the current connection and reform a new one. It will also cause sends to be
922         // queued instead of sent. In case we're not the transport thread and instead it is currently stuck in
923         // a Receive (I don't entirely trust the connection to immediately fail these on a network problem)
924         // we'll call CancelReceive() to abort the operation. The transport thread itself will handle the
925         // actual Destroy() (having one thread do this management greatly simplifies things).
926         m_eState = SS_Resync_NC;
927         m_pipe.Disconnect();
928         break;
929
930     default:
931         _ASSERTE(!"Unknown session state");
932     }
933     
934     if (!fCallerHoldsStateLock)
935         m_sStateLock.Leave();
936 }
937
938 // Scan the send queue and discard any messages which have been processed by the other side according to the
939 // specified ID). Messages waiting on a reply message (e.g. MT_GetDCB) will be retained until that reply is
940 // processed. FlushSendQueue will take the state lock.
941 void DbgTransportSession::FlushSendQueue(DWORD dwLastProcessedId)
942 {
943     // Must access the send queue under the state lock.
944     TransportLockHolder sLockHolder(&m_sStateLock);
945
946     // Note that message headers (and data blocks) may be encrypted. Use the cached fields in the Message
947     // structure to compare message IDs and types.
948
949     Message *pMsg = m_pSendQueueFirst;
950     Message *pLastMsg = NULL;
951     while (pMsg)
952     {
953         if (pMsg->m_sHeader.m_dwId <= dwLastProcessedId)
954         {
955             // Message has been seen and processed by other side.
956             // Check if we can discard it (i.e. it's not waiting on a reply message that needs the original
957             // request to hang around).
958 #ifdef RIGHT_SIDE_COMPILE
959             MessageType eType = pMsg->m_sHeader.m_eType;
960             if (eType != MT_ReadMemory &&
961                 eType != MT_WriteMemory &&
962                 eType != MT_VirtualUnwind &&
963                 eType != MT_GetDCB &&
964                 eType != MT_SetDCB &&
965                 eType != MT_GetAppDomainCB)
966 #endif // RIGHT_SIDE_COMPILE
967             {
968 #ifdef RIGHT_SIDE_COMPILE
969                 _ASSERTE(eType == MT_Event);
970 #endif // RIGHT_SIDE_COMPILE
971
972                 // We can discard this message.
973
974                 // Unlink it from the queue.
975                 if (pLastMsg == NULL)
976                     m_pSendQueueFirst = pMsg->m_pNext;
977                 else
978                     pLastMsg->m_pNext = pMsg->m_pNext;
979                 if (m_pSendQueueLast == pMsg)
980                     m_pSendQueueLast = pLastMsg;
981
982                 Message *pDiscardMsg = pMsg;
983                 pMsg = pMsg->m_pNext;
984
985                 // If the message is a copy deallocate it (and the data block associated with it).
986                 if (pDiscardMsg->m_pOrigMessage != pDiscardMsg)
987                 {
988                     if (pDiscardMsg->m_pbDataBlock)
989                         delete [] pDiscardMsg->m_pbDataBlock;
990                     delete pDiscardMsg;
991                 }
992
993                 continue;
994             }
995         }
996
997         pLastMsg = pMsg;
998         pMsg = pMsg->m_pNext;
999     }
1000 }
1001
1002 #ifdef RIGHT_SIDE_COMPILE
1003 // Perform processing required to complete a request (such as MT_GetDCB) once a reply comes in. This includes
1004 // reading data from the connection into the output buffer, removing the original message from the send queue
1005 // and signalling the completion event. Returns true if no network error was encountered.
1006 bool DbgTransportSession::ProcessReply(MessageHeader *pHeader)
1007 {
1008     // Locate original message on the send queue.
1009     Message *pMsg = RemoveMessageFromSendQueue(pHeader->m_dwReplyId);
1010
1011     // This can happen if the thread blocked waiting for the replyl message has waken up because the debuggee
1012     // process has terminated.  See code:DbgTransportSession::SendRequestMessageAndWait() for more info.
1013     if (pMsg == NULL)
1014     {
1015         return true;
1016     }
1017
1018     // If there is a reply block but the caller hasn't specified a reply buffer.
1019     // This combination is not used any more.
1020     _ASSERTE(! ((pHeader->m_cbDataBlock != (DWORD)0) && (pMsg->m_pbReplyBlock == (PBYTE)NULL)) );
1021
1022     // If there was an output buffer provided then we copy the data block in the reply into it (perhaps
1023     // decrypting it first). If the reply header indicates there is no data block then presumably the request
1024     // failed (which should be indicated in the TypeSpecificData of the reply, ala MT_ReadMemory).
1025     if (pMsg->m_pbReplyBlock && pHeader->m_cbDataBlock)
1026     {
1027         _ASSERTE(pHeader->m_cbDataBlock == pMsg->m_cbReplyBlock);
1028         if (!ReceiveBlock(pMsg->m_pbReplyBlock, pMsg->m_cbReplyBlock))
1029         {
1030             // Whoops. We hit an error trying to read the reply data. We need to push the original message
1031             // back on the queue and await a retry. Since this message must have been seen by the other side
1032             // we don't need to put it on the queue in order (it will never be resent). Easiest just to put it
1033             // on the head.
1034             {
1035                 TransportLockHolder sLockHolder(&m_sStateLock);
1036                 pMsg->m_pNext = m_pSendQueueFirst;
1037                 m_pSendQueueFirst = pMsg;
1038                 if (m_pSendQueueLast == NULL)
1039                     m_pSendQueueLast = pMsg;
1040                 return false;
1041             } // Leave m_sStateLock
1042         }
1043     }
1044
1045     // Copy TypeSpecificData from the reply back into the original message (it can contain additional status).
1046     // Be careful to update the real original message (the version on the queue will be a copy if we're using
1047     // a secure session).
1048     pMsg->m_pOrigMessage->m_sHeader.TypeSpecificData = pHeader->TypeSpecificData;
1049
1050     // **** IMPORTANT NOTE ****
1051     // We're about to cause a side-effect visible to our client. From here on out (until we update the
1052     // session's idea of the last incoming message we processed back in the transport thread's main loop) we
1053     // must avoid any failures. If we fail before the update the other side will re-send the message which is
1054     // bad if we've already processed it. See the comment near the start of the SS_Open message dispatch logic
1055     // for more details.
1056     // **** IMPORTANT NOTE ****
1057
1058     // Signal the completion event.
1059     SignalReplyEvent(pMsg);
1060
1061     return true;
1062 }
1063
1064 //---------------------------------------------------------------------------------------
1065 //
1066 // Upon receiving a reply message, signal the event on the message to wake up the thread waiting for 
1067 // the reply message and close the handle to the event.
1068 //
1069 // Arguments:
1070 //    pMessage - the reply message to be processed
1071 //
1072
1073 void DbgTransportSession::SignalReplyEvent(Message * pMessage)
1074 {
1075     // Make a local copy of the event handle.  As soon as we signal the event, the thread blocked waiting on 
1076     // the reply may wake up and trash the message.  See code:DbgTransportSession::SendRequestMessageAndWait() 
1077     // for more info.
1078     HANDLE hReplyEvent = pMessage->m_hReplyEvent;
1079     _ASSERTE(hReplyEvent != NULL);
1080
1081     SetEvent(hReplyEvent);
1082     CloseHandle(hReplyEvent);
1083 }
1084
1085 //---------------------------------------------------------------------------------------
1086 //
1087 // Given a message ID, find the matching message in the send queue.  If there is no match, return NULL.
1088 // If there is a match, remove the message from the send queue and return it.
1089 //
1090 // Arguments:
1091 //    dwMessageId - the ID of the message to retrieve
1092 //
1093 // Return Value:
1094 //    NULL if the specified message cannot be found.
1095 //    Otherwise return the specified message with the side effect that it's also removed from the send queue.
1096 //
1097 // Notes:
1098 //    The caller is NOT responsible for taking the state lock.  This function will do that.
1099 //
1100
1101 DbgTransportSession::Message * DbgTransportSession::RemoveMessageFromSendQueue(DWORD dwMessageId)
1102 {
1103     // Locate original message on the send queue.
1104     Message *pMsg = NULL;
1105     {
1106         TransportLockHolder sLockHolder(&m_sStateLock);
1107
1108         pMsg = m_pSendQueueFirst;
1109         Message *pLastMsg = NULL;
1110
1111         while (pMsg)
1112         {
1113             if (dwMessageId == pMsg->m_sHeader.m_dwId)
1114             {
1115                 // Found the original message that this is a reply to. Unlink it.
1116                 if (pLastMsg == NULL)
1117                     m_pSendQueueFirst = pMsg->m_pNext;
1118                 else
1119                     pLastMsg->m_pNext = pMsg->m_pNext;
1120                 
1121                 if (m_pSendQueueLast == pMsg)
1122                     m_pSendQueueLast = pLastMsg;
1123                 break;
1124             }
1125
1126             pLastMsg = pMsg;
1127             pMsg = pMsg->m_pNext;
1128         }
1129     } // Leave m_sStateLock
1130
1131     // could be NULL
1132     return pMsg;
1133 }
1134 #endif
1135
1136 #ifndef RIGHT_SIDE_COMPILE
1137
1138 #ifdef FEATURE_PAL
1139 __attribute__((noinline))
1140 __attribute__((optnone))
1141 static void 
1142 ProbeMemory(__in_ecount(cbBuffer) volatile PBYTE pbBuffer, DWORD cbBuffer, bool fWriteAccess)
1143 {
1144     // Need an throw in this function to fool the C++ runtime into handling the 
1145     // possible h/w exception below.
1146     if (pbBuffer == NULL)
1147     {
1148         throw PAL_SEHException();
1149     }
1150
1151     // Simple one byte at a time probing
1152     while (cbBuffer > 0)
1153     {
1154         volatile BYTE read = *pbBuffer;
1155         if (fWriteAccess)
1156         {
1157             *pbBuffer = read;
1158         }
1159         ++pbBuffer;
1160         --cbBuffer;
1161     }
1162 }
1163 #endif // FEATURE_PAL
1164
1165 // Check read and optionally write memory access to the specified range of bytes. Used to check
1166 // ReadProcessMemory and WriteProcessMemory requests.
1167 HRESULT DbgTransportSession::CheckBufferAccess(__in_ecount(cbBuffer) PBYTE pbBuffer, DWORD cbBuffer, bool fWriteAccess)
1168 {
1169     // check for integer overflow
1170     if ((pbBuffer + cbBuffer) < pbBuffer)
1171     {
1172         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
1173     }
1174
1175     // VirtualQuery doesn't know much about memory allocated outside of PAL's VirtualAlloc 
1176     // that's why on Unix we can't rely on in to detect invalid memory reads  
1177 #ifndef FEATURE_PAL
1178     do 
1179     {
1180         // Find the attributes of the largest set of pages with common attributes starting from our base address.
1181         MEMORY_BASIC_INFORMATION sMemInfo;
1182         VirtualQuery(pbBuffer, &sMemInfo, sizeof(sMemInfo));
1183
1184         DbgTransportLog(LC_Proxy, "CBA(%08X,%08X): State:%08X Protect:%08X BA:%08X RS:%08X",
1185                         pbBuffer, cbBuffer, sMemInfo.State, sMemInfo.Protect, sMemInfo.BaseAddress, sMemInfo.RegionSize);
1186
1187         // The memory must be committed (i.e. have physical pages or backing store).
1188         if (sMemInfo.State != MEM_COMMIT)
1189             return HRESULT_FROM_WIN32(ERROR_INVALID_ADDRESS);
1190
1191         // Check for compatible page protections. Lower byte of Protect has these (upper bytes have options we're
1192         // not interested in, cache modes and the like.
1193         DWORD dwProtect = sMemInfo.Protect & 0xff;
1194
1195         if (fWriteAccess &&
1196             ((dwProtect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READWRITE | PAGE_WRITECOPY)) == 0))
1197             return HRESULT_FROM_WIN32(ERROR_NOACCESS);
1198         else if (!fWriteAccess &&
1199             ((dwProtect & (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY)) == 0))
1200             return HRESULT_FROM_WIN32(ERROR_NOACCESS);
1201
1202         // If the requested range is bigger than the region we have queried, 
1203         // we need to continue on to check the next region.
1204         if ((pbBuffer + cbBuffer) > ((PBYTE)sMemInfo.BaseAddress + sMemInfo.RegionSize))
1205         {
1206             PBYTE pbRegionEnd = reinterpret_cast<PBYTE>(sMemInfo.BaseAddress) + sMemInfo.RegionSize;
1207             cbBuffer = (DWORD)((pbBuffer + cbBuffer) - pbRegionEnd);
1208             pbBuffer = pbRegionEnd;
1209         }
1210         else
1211         {
1212             // We are done.  Set cbBuffer to 0 to exit this loop.
1213             cbBuffer = 0;
1214         }
1215     }
1216     while (cbBuffer > 0);
1217 #else
1218     try
1219     {
1220         // Need to explicit h/w exception holder so to catch them in ProbeMemory
1221         CatchHardwareExceptionHolder __catchHardwareException;
1222
1223         ProbeMemory(pbBuffer, cbBuffer, fWriteAccess);
1224     }
1225     catch(...)
1226     {
1227         return HRESULT_FROM_WIN32(ERROR_INVALID_ADDRESS);
1228     }
1229 #endif
1230
1231     // The specified region has passed all of our checks.
1232     return S_OK;
1233 }
1234
1235 #endif // !RIGHT_SIDE_COMPILE
1236
1237 // Initialize all session state to correct starting values. Used during Init() and on the LS when we
1238 // gracefully close one session and prepare for another.
1239 void DbgTransportSession::InitSessionState()
1240 {
1241     DBG_TRANSPORT_INC_STAT(Sessions);
1242
1243     m_dwMajorVersion = kCurrentMajorVersion;
1244     m_dwMinorVersion = kCurrentMinorVersion;
1245
1246     memset(&m_sSessionID, 0, sizeof(m_sSessionID));
1247
1248     m_pSendQueueFirst = NULL;
1249     m_pSendQueueLast = NULL;
1250
1251     m_dwNextMessageId = 1;
1252     m_dwLastMessageIdSeen = 0;
1253
1254     m_eState = SS_Opening_NC;
1255
1256     m_cValidEventBuffers = 0;
1257     m_idxEventBufferHead = 0;
1258     m_idxEventBufferTail = 0;
1259 }
1260
1261 // The entry point of the transport worker thread. This one's static, so we immediately dispatch to an
1262 // instance method version defined below for convenience in the implementation.
1263 DWORD WINAPI DbgTransportSession::TransportWorkerStatic(LPVOID pvContext)
1264 {
1265     ((DbgTransportSession*)pvContext)->TransportWorker();
1266
1267     // Nobody looks at this result, the choice of 0 is arbitrary.
1268     return 0;
1269 }
1270
1271 // Macros used to simplify error and state transition handling within the transport worker loop. Errors are
1272 // classified as either transient or critical. Transient errors (typically those from network operations)
1273 // result in the connection being closed and rebuilt: we should eventually recover from them. Critical errors
1274 // are those that cause a transition to the SS_Closed state, which the session never recovers from. These are
1275 // normally due to protocol errors where we want to shut the transport down in case they are of malicious
1276 // origin.
1277 #define HANDLE_TRANSIENT_ERROR() do {           \
1278     HandleNetworkError(false);                  \
1279     m_pipe.Disconnect();                        \
1280     goto ResetConnection;                       \
1281 } while (false)
1282
1283 #define HANDLE_CRITICAL_ERROR() do {            \
1284     m_eState = SS_Closed;                       \
1285     goto Shutdown;                              \
1286 } while (false)
1287
1288 #ifdef _PREFAST_
1289 #pragma warning(push)
1290 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1291 #endif
1292 void DbgTransportSession::TransportWorker()
1293 {
1294     _ASSERTE(m_eState == SS_Opening_NC);
1295
1296     // Loop until shutdown. Each loop iteration involves forming a connection (or waiting for one to form)
1297     // followed by processing incoming messages on that connection until there's a failure (either here of
1298     // from a send on another thread) or the session shuts down. The connection is then closed and discarded
1299     // and we either go round the loop again (to recover our previous session state) or exit the method as
1300     // part of shutdown.
1301   ResetConnection:
1302     while (m_eState != SS_Closed)
1303     {
1304         _ASSERTE(m_eState == SS_Opening_NC || m_eState == SS_Resync_NC || m_eState == SS_Closed);
1305
1306         DbgTransportLog(LC_Proxy, "Forming new connection");
1307
1308 #ifdef RIGHT_SIDE_COMPILE
1309         // The session is definitely not open at this point.
1310         ResetEvent(m_hSessionOpenEvent);
1311
1312         // On the right side we initiate the connection via Connect(). A failure is dealt with by waiting a
1313         // little while and retrying (the LS may take a little while to set up). If there's nobody listening
1314         // the debugger will eventually get bored waiting for us and shutdown the session, which will
1315         // terminate this loop.
1316         ConnStatus eStatus;
1317         if (DBG_TRANSPORT_SHOULD_INJECT_FAULT(Connect))
1318             eStatus = SCS_NetworkFailure;
1319         else
1320         {
1321             if (m_pipe.Connect(m_pid))
1322             {
1323                 eStatus = SCS_Success;
1324             }
1325             else
1326             {
1327                 //not really sure that this is the real failure
1328                 //TODO: we probably need to analyse GetErrorCode() here
1329                 eStatus = SCS_NoListener; 
1330             }
1331         }
1332
1333         if (eStatus != SCS_Success)
1334         {
1335             DbgTransportLog(LC_Proxy, "AllocateConnection() failed with %u\n", eStatus);
1336             DBG_TRANSPORT_INC_STAT(MiscErrors);
1337             _ASSERTE(m_pipe.GetState() != TwoWayPipe::ClientConnected);
1338             Sleep(1000);
1339             continue;
1340         }
1341 #else // RIGHT_SIDE_COMPILE
1342         ConnStatus eStatus;
1343         if (DBG_TRANSPORT_SHOULD_INJECT_FAULT(Accept))
1344             eStatus = SCS_NetworkFailure;
1345         else
1346         {
1347             DWORD pid = GetCurrentProcessId(); 
1348             if (m_pipe.CreateServer(pid) && m_pipe.WaitForConnection())
1349             {
1350                 eStatus = SCS_Success;
1351             }
1352             else
1353             {
1354                 //not really sure that this is the real failure
1355                 //TODO: we probably need to analyse GetErrorCode() here
1356                 eStatus = SCS_NoListener; 
1357             }
1358         }
1359
1360         if (eStatus != SCS_Success)
1361         {
1362             DbgTransportLog(LC_Proxy, "Accept() failed with %u\n", eStatus);
1363             DBG_TRANSPORT_INC_STAT(MiscErrors);
1364             _ASSERTE(m_pipe.GetState() != TwoWayPipe::ServerConnected);
1365             Sleep(1000);
1366             continue;
1367         }
1368
1369         // Note that when resynching a session we may let in a connection from a different debugger. That's
1370         // OK, we'll reject his SessionRequest message in due course and drop the connection.
1371 #endif // RIGHT_SIDE_COMPILE
1372
1373         DBG_TRANSPORT_INC_STAT(Connections);
1374
1375         // We now have a connection. Transition to the next state (either SS_Opening or SS_Resync). The
1376         // primary purpose of this state transition is to let other threads know that this thread might now be
1377         // blocked on a Receive() on the newly formed connection (important if they want to transition the state
1378         // to SS_Closed).
1379         {
1380             TransportLockHolder sLockHolder(&m_sStateLock);
1381
1382             if (m_eState == SS_Closed)
1383                 break;
1384             else if (m_eState == SS_Opening_NC)
1385                 m_eState = SS_Opening;
1386             else if (m_eState == SS_Resync_NC)
1387                 m_eState = SS_Resync;
1388             else
1389                 _ASSERTE(!"Bad session state");
1390         } // Leave m_sStateLock
1391
1392
1393         // Now we have a connection in place. Start reading messages and processing them. Which messages are
1394         // valid depends on whether we're in SS_Opening or SS_Resync (the state can change at any time
1395         // asynchronously to us to either SS_Closed or SS_Resync_NC but we're guaranteed the connection stays
1396         // valid (though not necessarily useful) until we notice this state change and Destroy() it ourself).
1397         // We check the state after each network operation.
1398
1399         // During the SS_Opening and SS_Resync states we're guarantee to be the only thread posting sends, so
1400         // we can break the rules and use SendBlock without acquiring the state lock. (We use SendBlock a lot
1401         // during these phases because we're using simple Session* messages which don't require the extra
1402         // processing SendMessage gives us such as encryption or placement on the send queue).
1403
1404         MessageHeader   sSendHeader;
1405         MessageHeader   sReceiveHeader;
1406
1407         memset(&sSendHeader, 0, sizeof(MessageHeader));
1408
1409         if (m_eState == SS_Opening)
1410         {
1411 #ifdef RIGHT_SIDE_COMPILE
1412             // The right side actually starts things off by sending a SessionRequest message.
1413
1414             SessionRequestData sDataBlock;
1415
1416             sSendHeader.m_eType = MT_SessionRequest;
1417             sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion;
1418             sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = kCurrentMinorVersion;
1419
1420             // The start of the data block always contains a session ID. This is a GUID randomly generated at
1421             // Init() time.
1422             sSendHeader.m_cbDataBlock = sizeof(SessionRequestData);
1423             memcpy(&sDataBlock.m_sSessionID, &m_sSessionID, sizeof(m_sSessionID));
1424
1425             // Send the header block followed by the data block. For failures during SS_Opening we just close
1426             // the connection and retry from the beginning (the failing send will already have caused a
1427             // transition into SS_Opening_NC. No need to use the same resend logic that SS_Resync does, since
1428             // no user messages have been sent and we can simply recreate the SessionRequest.
1429             DbgTransportLog(LC_Session, "Sending 'SessionRequest'");
1430             DBG_TRANSPORT_INC_STAT(SentSessionRequest);
1431             if (!SendBlock((PBYTE)&sSendHeader, sizeof(MessageHeader)) ||
1432                 !SendBlock((PBYTE)&sDataBlock, sSendHeader.m_cbDataBlock))
1433                 HANDLE_TRANSIENT_ERROR();
1434
1435             // Wait for a reply.
1436             if (!ReceiveBlock((PBYTE)&sReceiveHeader, sizeof(MessageHeader)))
1437                 HANDLE_TRANSIENT_ERROR();
1438
1439             DbgTransportLogMessageReceived(&sReceiveHeader);
1440
1441             // This should be either a SessionAccept or SessionReject. Any other message type will be treated
1442             // as a SessionReject (i.e. an unrecoverable failure that will leave the session in SS_Closed
1443             // permanently).
1444             if (sReceiveHeader.m_eType != MT_SessionAccept)
1445             {
1446                 _ASSERTE(!"Unexpected response to SessionRequest");
1447                 HANDLE_CRITICAL_ERROR();
1448             }
1449
1450             // Validate the SessionAccept.
1451             if (sReceiveHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion != kCurrentMajorVersion ||
1452                 sReceiveHeader.m_cbDataBlock != (DWORD)0)
1453             {
1454                 _ASSERTE(!"Malformed SessionAccept received");
1455                 HANDLE_CRITICAL_ERROR();
1456             }
1457
1458             // The LS might have negotiated the minor protocol version down.
1459             m_dwMinorVersion = sReceiveHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion;
1460 #else // RIGHT_SIDE_COMPILE
1461
1462             // On the left side we wait for a SessionRequest first.
1463             if (!ReceiveBlock((PBYTE)&sReceiveHeader, sizeof(MessageHeader)))
1464                 HANDLE_TRANSIENT_ERROR();
1465
1466             DbgTransportLogMessageReceived(&sReceiveHeader);
1467
1468             if (sReceiveHeader.m_eType != MT_SessionRequest)
1469             {
1470                 _ASSERTE(!"Unexpected message type");
1471                 HANDLE_CRITICAL_ERROR();
1472             }
1473
1474             // Validate the SessionRequest.
1475             if (sReceiveHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion != kCurrentMajorVersion ||
1476                 sReceiveHeader.m_cbDataBlock != (DWORD)sizeof(SessionRequestData))
1477             {
1478                 // Send a SessionReject message with the reason for rejection.
1479                 sSendHeader.m_eType = MT_SessionReject;
1480                 sSendHeader.TypeSpecificData.SessionReject.m_eReason = RR_IncompatibleVersion;
1481                 sSendHeader.TypeSpecificData.SessionReject.m_dwMajorVersion = kCurrentMajorVersion;
1482                 sSendHeader.TypeSpecificData.SessionReject.m_dwMinorVersion = kCurrentMinorVersion;
1483
1484                 DbgTransportLog(LC_Session, "Sending 'SessionReject(RR_IncompatibleVersion)'");
1485                 DBG_TRANSPORT_INC_STAT(SentSessionReject);
1486
1487                 SendBlock((PBYTE)&sSendHeader, sizeof(MessageHeader));
1488
1489                 // Go back into the opening state rather than closed because we want to give the RS a chance
1490                 // to correct the problem and try again.
1491                 HANDLE_TRANSIENT_ERROR();
1492             }
1493
1494             // Read the data block.
1495             SessionRequestData sDataBlock;
1496             if (!ReceiveBlock((PBYTE)&sDataBlock, sizeof(SessionRequestData)))
1497                 HANDLE_TRANSIENT_ERROR();
1498
1499             // If the RS only understands a lower minor protocol version than us then remember that fact.
1500             if (sReceiveHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion < m_dwMinorVersion)
1501                 m_dwMinorVersion = sReceiveHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion;
1502
1503             // Send a SessionAccept message back.
1504             sSendHeader.m_eType = MT_SessionAccept;
1505             sSendHeader.m_cbDataBlock = 0;
1506             sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion;
1507             sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = m_dwMinorVersion;
1508
1509             DbgTransportLog(LC_Session, "Sending 'SessionAccept'");
1510             DBG_TRANSPORT_INC_STAT(SentSessionAccept);
1511
1512             if (!SendBlock((PBYTE)&sSendHeader, sizeof(MessageHeader)))
1513                 HANDLE_TRANSIENT_ERROR();
1514 #endif // RIGHT_SIDE_COMPILE
1515
1516             // Everything pans out, we have a session formed. But we must send messages that queued up
1517             // before transitioning the state to open (otherwise a racing send could sneak in ahead).
1518
1519             // Must access the send queue under the state lock.
1520             {
1521                 TransportLockHolder sLockHolder(&m_sStateLock);
1522                 Message *pMsg = m_pSendQueueFirst;
1523                 while (pMsg)
1524                 {
1525                     if (SendBlock((PBYTE)&pMsg->m_sHeader, sizeof(MessageHeader)) && pMsg->m_pbDataBlock)
1526                         SendBlock(pMsg->m_pbDataBlock, pMsg->m_cbDataBlock);
1527                     pMsg = pMsg->m_pNext;
1528                 }
1529             
1530                 // Check none of the sends failed.
1531                 if (m_eState != SS_Opening)
1532                 {
1533                     m_pipe.Disconnect();
1534                     continue;
1535                 }
1536             } // Leave m_sStateLock
1537
1538             // Finally we can transition to SS_Open.
1539             {
1540                 TransportLockHolder sLockHolder(&m_sStateLock);
1541                 if (m_eState == SS_Closed)
1542                     break;
1543                 else if (m_eState == SS_Opening)
1544                     m_eState = SS_Open;
1545                 else
1546                     _ASSERTE(!"Bad session state");
1547             } // Leave m_sStateLock
1548
1549 #ifdef RIGHT_SIDE_COMPILE
1550             // Signal any WaitForSessionToOpen() waiters that we've gotten to SS_Open.
1551             SetEvent(m_hSessionOpenEvent);
1552 #endif // RIGHT_SIDE_COMPILE
1553
1554             // We're ready to begin receiving normal incoming messages now.
1555         }
1556         else
1557         {
1558             // The SS_Resync case. Send a message indicating the last message we saw from the other side and
1559             // wait for a similar message to arrive for us.
1560
1561             sSendHeader.m_eType = MT_SessionResync;
1562             sSendHeader.m_dwLastSeenId = m_dwLastMessageIdSeen;
1563
1564             DbgTransportLog(LC_Session, "Sending 'SessionResync'");
1565             DBG_TRANSPORT_INC_STAT(SentSessionResync);
1566
1567             if (!SendBlock((PBYTE)&sSendHeader, sizeof(MessageHeader)))
1568                 HANDLE_TRANSIENT_ERROR();
1569
1570             if (!ReceiveBlock((PBYTE)&sReceiveHeader, sizeof(MessageHeader)))
1571                 HANDLE_TRANSIENT_ERROR();
1572
1573 #ifndef RIGHT_SIDE_COMPILE
1574             if (sReceiveHeader.m_eType == MT_SessionRequest)
1575             {
1576                 DbgTransportLogMessageReceived(&sReceiveHeader);
1577
1578                 // This SessionRequest could be from a different debugger. In this case we should send a
1579                 // SessionReject to let them know we're not available and close the connection so we can
1580                 // re-listen for the original debugger.
1581                 // Or it could be the original debugger re-sending the SessionRequest because the connection
1582                 // died as we sent the SessionAccept.
1583                 // We distinguish the two cases by looking at the session ID in the request.
1584                 bool fRequestResend = false;
1585
1586                 // Only read the data block if it matches our expectations of its size.
1587                 if (sReceiveHeader.m_cbDataBlock == (DWORD)sizeof(SessionRequestData))
1588                 {
1589                     SessionRequestData sDataBlock;
1590                     if (!ReceiveBlock((PBYTE)&sDataBlock, sizeof(SessionRequestData)))
1591                         HANDLE_TRANSIENT_ERROR();
1592
1593                     // Check the session ID for a match.
1594                     if (memcmp(&sDataBlock.m_sSessionID, &m_sSessionID, sizeof(m_sSessionID)) == 0)
1595                         // OK, everything checks out and this is a valid re-send of a SessionRequest.
1596                         fRequestResend = true;
1597                 }
1598
1599                 if (fRequestResend)
1600                 {
1601                     // The RS never got our SessionAccept. We must resend it.
1602                     memset(&sSendHeader, 0, sizeof(MessageHeader));
1603                     sSendHeader.m_eType = MT_SessionAccept;
1604                     sSendHeader.m_cbDataBlock = 0;
1605                     sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion;
1606                     sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = m_dwMinorVersion;
1607
1608                     DbgTransportLog(LC_Session, "Sending 'SessionAccept'");
1609                     DBG_TRANSPORT_INC_STAT(SentSessionAccept);
1610
1611                     if (!SendBlock((PBYTE)&sSendHeader, sizeof(MessageHeader)))
1612                         HANDLE_TRANSIENT_ERROR();
1613
1614                     // Now simply reset the connection. The RS should get the SessionAccept and transition to
1615                     // SS_Open then detect the connection loss and transition to SS_Resync_NC, which will
1616                     // finally sync the two sides.
1617                     HANDLE_TRANSIENT_ERROR();
1618                 }
1619                 else
1620                 {
1621                     // This is the case where we must reject the request.
1622                     memset(&sSendHeader, 0, sizeof(MessageHeader));
1623                     sSendHeader.m_eType = MT_SessionReject;
1624                     sSendHeader.TypeSpecificData.SessionReject.m_eReason = RR_AlreadyAttached;
1625                     sSendHeader.TypeSpecificData.SessionReject.m_dwMajorVersion = kCurrentMajorVersion;
1626                     sSendHeader.TypeSpecificData.SessionReject.m_dwMinorVersion = kCurrentMinorVersion;
1627
1628                     DbgTransportLog(LC_Session, "Sending 'SessionReject(RR_AlreadyAttached)'");
1629                     DBG_TRANSPORT_INC_STAT(SentSessionReject);
1630
1631                     SendBlock((PBYTE)&sSendHeader, sizeof(MessageHeader));
1632
1633                     HANDLE_TRANSIENT_ERROR();
1634                 }
1635             }
1636 #endif // !RIGHT_SIDE_COMPILE
1637
1638             DbgTransportLogMessageReceived(&sReceiveHeader);
1639
1640             // Handle all other invalid message types by shutting down (it may be an attempt to subvert the
1641             // protocol).
1642             if (sReceiveHeader.m_eType != MT_SessionResync)
1643             {
1644                 _ASSERTE(!"Unexpected message type during SS_Resync");
1645                 HANDLE_CRITICAL_ERROR();
1646             }
1647
1648             // We've got our resync message. Go through the send queue and resend any messages that haven't
1649             // been processed by the other side. Those that have been processed can be discarded (unless
1650             // they're waiting for another form of higher level acknowledgement, such as a reply message).
1651
1652             // Discard unneeded messages first.
1653             FlushSendQueue(sReceiveHeader.m_dwLastSeenId);
1654
1655             // Must access the send queue under the state lock.
1656             {
1657                 TransportLockHolder sLockHolder(&m_sStateLock);
1658
1659                 Message *pMsg = m_pSendQueueFirst;
1660                 while (pMsg)
1661                 {
1662                     if (pMsg->m_sHeader.m_dwId > sReceiveHeader.m_dwLastSeenId)
1663                     {
1664                         // The other side never saw this message, re-send it.
1665                         DBG_TRANSPORT_INC_STAT(Resends);
1666                         if (SendBlock((PBYTE)&pMsg->m_sHeader, sizeof(MessageHeader)) && pMsg->m_pbDataBlock)
1667                             SendBlock(pMsg->m_pbDataBlock, pMsg->m_cbDataBlock);
1668                     }
1669                     pMsg = pMsg->m_pNext;
1670                 }
1671
1672                 // Finished processing queued sends. We can transition to the SS_Open state now as long as there
1673                 // wasn't a send failure or an asynchronous Shutdown().
1674                 if (m_eState == SS_Resync)
1675                     m_eState = SS_Open;
1676                 else if (m_eState == SS_Closed)
1677                     break;
1678                 else if (m_eState == SS_Resync_NC)
1679                 {
1680                     m_pipe.Disconnect();
1681                     continue;
1682                 }
1683                 else
1684                     _ASSERTE(!"Bad session state");
1685             } // Leave m_sStateLock
1686         }
1687
1688         // Once we get here we should be in SS_Open (can't assert this because Shutdown() can throw the state
1689         // into SS_Closed and we've just released SendMessage() calls on other threads that can transition us
1690         // into SS_Resync).
1691
1692         // We now loop receiving messages and processing them until the state changes.
1693         while (m_eState == SS_Open)
1694         {
1695             // temporary data block used in DCB messages
1696             DebuggerIPCControlBlockTransport dcbt;
1697
1698             // temporary virtual stack unwind context buffer
1699             CONTEXT frameContext;
1700
1701             // Read a message header block.
1702             if (!ReceiveBlock((PBYTE)&sReceiveHeader, sizeof(MessageHeader)))
1703                 HANDLE_TRANSIENT_ERROR();
1704
1705             // Since we care about security here, perform some additional validation checks that make it
1706             // harder for a malicious sender to attack with random message data.
1707             if (sReceiveHeader.m_eType > MT_GetAppDomainCB ||
1708                 (sReceiveHeader.m_dwId <= m_dwLastMessageIdSeen &&
1709                  sReceiveHeader.m_dwId != (DWORD)0) ||
1710                 (sReceiveHeader.m_dwReplyId >= m_dwNextMessageId &&
1711                  sReceiveHeader.m_dwReplyId != (DWORD)0) ||
1712                 (sReceiveHeader.m_dwLastSeenId >= m_dwNextMessageId &&
1713                  sReceiveHeader.m_dwLastSeenId != (DWORD)0))
1714             {
1715                 _ASSERTE(!"Incoming message header looks bogus");
1716                 HANDLE_CRITICAL_ERROR();
1717             }
1718
1719             DbgTransportLogMessageReceived(&sReceiveHeader);
1720
1721             // Flush any entries in our send queue for messages that the other side has just confirmed
1722             // processed with this message.
1723             FlushSendQueue(sReceiveHeader.m_dwLastSeenId);
1724
1725 #ifndef RIGHT_SIDE_COMPILE
1726             // State variables to track whether this message needs a reply and if so whether it consists of a
1727             // header only or a header and an optional data block.
1728             bool    fReplyRequired = false;
1729             PBYTE   pbOptReplyData = NULL;
1730             DWORD   cbOptReplyData = 0;
1731             HRESULT hr             = E_FAIL;
1732
1733             // if you change the lifetime of resultBuffer, make sure you change pbOptReplyData to match.
1734             // In some cases pbOptReplyData will point at the memory held alive in resultBuffer
1735             WriteBuffer resultBuffer;
1736             ReadBuffer  receiveBuffer;
1737
1738 #endif // RIGHT_SIDE_COMPILE
1739
1740             // Dispatch based on message type.
1741             //
1742             // **** IMPORTANT NOTE ****
1743             //
1744             // We must be very careful wrt to updating m_dwLastMessageIdSeen here. If we update it too soon
1745             // (we haven't finished receiving the entire message, for instance) then the other side won't
1746             // re-send the message on failure and we'll lose it. If we update it too late we might have
1747             // reported the message to our caller or produced any other side-effect we can't take back such as
1748             // sending a reply and then hit an error and reset the connection before we had a chance to record
1749             // the message as seen. In this case the other side will re-send the original message and we'll
1750             // repeat our actions, which is also very bad.
1751             //
1752             // So we must be very disciplined here.
1753             //
1754             // First we must read the message in its entirety (i.e. receive the data block if there is one)
1755             // without causing any side-effects. This ensures that any failure at this point will be handled
1756             // correctly (by the other side re-sending us the same message).
1757             // 
1758             // Then we process the message. At this point we are committed. The processing must always
1759             // succeed, or have no side-effect (that we care about) or we must have an additional scheme to
1760             // handle resynchronization in the event of failure. This ensures that we don't have the tricky
1761             // situation where we can't cope with a re-send of the message (because we've started processing
1762             // it) but can't report a failure to the other side (because we don't know how).
1763             //
1764             // Finally we must ensure that there is no error path between the completion of processing and
1765             // updating the m_dwLastMessageIdSeen field. This ensures we don't accidently get re-sent a
1766             // message we've processed completely (it's really just a sub-case of the rule above, but it's
1767             // worth pointing out explicitly since it can be a subtle problem).
1768             //
1769             // Request messages (such as MT_GetDCB) are an interesting case in point here. They all require a
1770             // reply and we can fail on the reply because we run out of system resources. This breaks the
1771             // second rule above (we fail halfway through processing). We should really preallocate enough
1772             // resources to send the reply before we begin processing of it but for now we don't since (a) the
1773             // SendMessage system isn't currently set up to make this easy and (b) we happen to know that all
1774             // the request types are effectively idempotent (even ReadMemory and WriteMemory since the RS is
1775             // holding the LS still while it does these). So instead we must carefully distinguish the case
1776             // where SendMessage fails without possibility of message transmission (e.g. out of memory) and
1777             // those where it fails for a transient network failure (where it will re-send the reply on
1778             // resync). This is easy enough to do since SendMessage returns a failure hresult for the first
1779             // case and success (and a state transition) for the second. In the first case we don't update
1780             // m_dwLastMessageIdSeen and instead wait for the request to be resent. In the second we make the
1781             // update because we know the reply will get through eventually.
1782             //
1783             // **** IMPORTANT NOTE ****
1784             switch (sReceiveHeader.m_eType)
1785             {
1786             case MT_SessionRequest:
1787             case MT_SessionAccept:
1788             case MT_SessionReject:
1789             case MT_SessionResync:
1790                 // Illegal messages at this time, fail the transport entirely.
1791                 m_eState = SS_Closed;
1792                 break;
1793
1794             case MT_SessionClose:
1795                 // Close is legal on the LS and transitions to the SS_Opening_NC state. It's illegal on the RS
1796                 // and should shutdown the transport.
1797 #ifdef RIGHT_SIDE_COMPILE
1798                 m_eState = SS_Closed;
1799                 break;
1800 #else // RIGHT_SIDE_COMPILE
1801                 // We need to do some state cleanup here, since when we reform a connection (if ever, it will
1802                 // be with a new session).
1803                 {
1804                     TransportLockHolder sLockHolder(&m_sStateLock);
1805
1806                     // Check we're still in a good state before a clean restart.
1807                     if (m_eState != SS_Open)
1808                     {
1809                         m_eState = SS_Closed;
1810                         break;
1811                     }
1812
1813                     m_pipe.Disconnect();
1814                 
1815                     // We could add code to drain the send queue here (like we have for SS_Closed at the end of
1816                     // this method) but I'm pretty sure we can only get a graceful session close with no
1817                     // outstanding sends. So just assert the queue is empty instead. If the assert fires and it's
1818                     // not due to an issue we can add the logic here).
1819                     _ASSERTE(m_pSendQueueFirst == NULL);
1820                     _ASSERTE(m_pSendQueueLast == NULL);
1821
1822                     // This will reset all session specific state and transition us to SS_Opening_NC.
1823                     InitSessionState();
1824                 } // Leave m_sStateLock
1825
1826                 goto ResetConnection;
1827 #endif // RIGHT_SIDE_COMPILE
1828
1829             case MT_Event:
1830             {
1831                 // Incoming debugger event.
1832
1833                 if (sReceiveHeader.m_cbDataBlock > CorDBIPC_BUFFER_SIZE)
1834                 {
1835                     _ASSERTE(!"Oversized Event");
1836                     HANDLE_CRITICAL_ERROR();
1837                 }
1838
1839                 // See if our array of buffered events has filled up. If so we'll need to re-allocate the
1840                 // array to expand it.
1841                 if (m_cValidEventBuffers == m_cEventBuffers)
1842                 {
1843                     // Allocate a larger array.
1844                     DWORD cNewEntries = m_cEventBuffers + 4;
1845                     DbgEventBufferEntry * pNewBuffers = (DbgEventBufferEntry *)new (nothrow) BYTE[cNewEntries * sizeof(DbgEventBufferEntry)];
1846                     if (pNewBuffers == NULL)
1847                         HANDLE_TRANSIENT_ERROR();
1848
1849                     // We must take the lock to swap the new array in. Although this thread is the only one
1850                     // that can expand the array, a client thread may be in GetNextEvent() reading from the
1851                     // old version.
1852                     {
1853                         TransportLockHolder sLockHolder(&m_sStateLock);
1854
1855                         // When we copy old array contents over we place the head of the list at the start of
1856                         // the new array for simplicity. If the head happened to be at the start of the old
1857                         // array anyway, this is even simpler.
1858                         if (m_idxEventBufferHead == 0)
1859                             memcpy(pNewBuffers, m_pEventBuffers, m_cEventBuffers * sizeof(DbgEventBufferEntry));
1860                         else
1861                         {
1862                             // Otherwise we need to perform the copy in two segments: first we copy the head
1863                             // of the list (starts at a non-zero index and runs to the end of the old array)
1864                             // into the start of the new array.
1865                             DWORD cHeadEntries = m_cEventBuffers - m_idxEventBufferHead;
1866
1867                             memcpy(pNewBuffers,
1868                                    &m_pEventBuffers[m_idxEventBufferHead],
1869                                    cHeadEntries * sizeof(DbgEventBufferEntry));
1870
1871                             // Then we copy the remaining portion from the beginning of the old array upto to
1872                             // the index of the head.
1873                             memcpy(&pNewBuffers[cHeadEntries],
1874                                    m_pEventBuffers,
1875                                    m_idxEventBufferHead * sizeof(DbgEventBufferEntry));
1876                         }
1877
1878                         // Delete the old array.
1879                         delete [] m_pEventBuffers;
1880
1881                         // Swap the new array in.
1882                         m_pEventBuffers = pNewBuffers;
1883                         m_cEventBuffers = cNewEntries;
1884
1885                         // The new array now has the head at index zero and the tail at the start of the
1886                         // new entries.
1887                         m_idxEventBufferHead = 0;
1888                         m_idxEventBufferTail = m_cValidEventBuffers;
1889                     }
1890                 }
1891
1892                 // We have at least one free buffer at this point (no threading issues, the only thread that
1893                 // can add entries is this one).
1894
1895                 // Receive event data into the tail buffer (we want to do this without holding the state lock
1896                 // and can do so safely since this is the only thread that can receive data and clients can do
1897                 // nothing that impacts the location of the tail of the buffer list).
1898                 if (!ReceiveBlock((PBYTE)&m_pEventBuffers[m_idxEventBufferTail].m_event, sReceiveHeader.m_cbDataBlock))
1899                     HANDLE_TRANSIENT_ERROR();
1900
1901                 {
1902                     m_pEventBuffers[m_idxEventBufferTail].m_type = sReceiveHeader.TypeSpecificData.Event.m_eIPCEventType;
1903
1904                     // We must take the lock to update the count of valid entries though, since clients can
1905                     // touch this field as well.
1906                     TransportLockHolder sLockHolder(&m_sStateLock);
1907
1908                     m_cValidEventBuffers++;
1909                     DWORD idxCurrentEvent = m_idxEventBufferTail;
1910
1911                     // Update tail of the list (strictly speaking this needn't be done under the lock, but the
1912                     // code in GetNextEvent() does read it for an assert.
1913                     m_idxEventBufferTail = (m_idxEventBufferTail + 1) % m_cEventBuffers;
1914
1915                     // If we just added the first valid event then wake up the client so they can call
1916                     // GetNextEvent().
1917                     if (m_cValidEventBuffers == 1)
1918                         SetEvent(m_rghEventReadyEvent[m_pEventBuffers[idxCurrentEvent].m_type]);
1919                 }
1920             }
1921             break;
1922
1923             case MT_ReadMemory:
1924 #ifdef RIGHT_SIDE_COMPILE                
1925                 if (!ProcessReply(&sReceiveHeader))
1926                     HANDLE_TRANSIENT_ERROR();
1927 #else // RIGHT_SIDE_COMPILE
1928                 // The RS wants to read our memory. First check the range requested is both committed and
1929                 // readable. If that succeeds we simply set the optional reply block to match the request region
1930                 // (i.e. we send the memory directly).
1931                 fReplyRequired = true;
1932
1933                 hr = CheckBufferAccess(sReceiveHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer,
1934                                        sReceiveHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer,
1935                                        false);
1936                 sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult = hr;
1937                 if (SUCCEEDED(hr))
1938                 {
1939                     pbOptReplyData = sReceiveHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer;
1940                     cbOptReplyData = sReceiveHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer;
1941                 }
1942 #endif // RIGHT_SIDE_COMPILE
1943                 break;
1944
1945             case MT_WriteMemory:
1946 #ifdef RIGHT_SIDE_COMPILE                
1947                 if (!ProcessReply(&sReceiveHeader))
1948                     HANDLE_TRANSIENT_ERROR();
1949 #else // RIGHT_SIDE_COMPILE
1950                 // The RS wants to write our memory.
1951                 if (sReceiveHeader.m_cbDataBlock != sReceiveHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer)
1952                 {
1953                     _ASSERTE(!"Inconsistent WriteMemory request");
1954                     HANDLE_CRITICAL_ERROR();
1955                 }
1956
1957                 fReplyRequired = true;
1958
1959                 // Check the range requested is both committed and writeable. If that succeeds we simply read
1960                 // the next incoming block into the destination buffer.
1961                 hr = CheckBufferAccess(sReceiveHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer,
1962                                        sReceiveHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer,
1963                                        true);
1964                 if (SUCCEEDED(hr))
1965                 {
1966                     if (!ReceiveBlock(sReceiveHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer,
1967                                       sReceiveHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer))
1968                         HANDLE_TRANSIENT_ERROR();
1969                 }
1970                 else
1971                 {
1972                     sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult = hr;
1973
1974                     // We might be failing the write attempt but we still need to read the update data to
1975                     // drain it from the connection or we'll become unsynchronized (i.e. we'll treat the start
1976                     // of the write data as the next message header). So read and discard the data into a
1977                     // dummy buffer.
1978                     BYTE    rgDummy[256];
1979                     DWORD   cbBytesToRead = sReceiveHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer;
1980                     while (cbBytesToRead)
1981                     {
1982                         DWORD cbTransfer = min(cbBytesToRead, sizeof(rgDummy));
1983                         if (!ReceiveBlock(rgDummy, cbTransfer))
1984                             HANDLE_TRANSIENT_ERROR();
1985                         cbBytesToRead -= cbTransfer;
1986                     }
1987                 }
1988 #endif // RIGHT_SIDE_COMPILE
1989                 break;
1990
1991             case MT_VirtualUnwind:
1992 #ifdef RIGHT_SIDE_COMPILE                
1993                 if (!ProcessReply(&sReceiveHeader))
1994                     HANDLE_TRANSIENT_ERROR();
1995 #else // RIGHT_SIDE_COMPILE
1996                 if (sReceiveHeader.m_cbDataBlock != (DWORD)sizeof(frameContext))
1997                 {
1998                     _ASSERTE(!"Inconsistent VirtualUnwind request");
1999                     HANDLE_CRITICAL_ERROR();
2000                 }
2001
2002                 if (!ReceiveBlock((PBYTE)&frameContext, sizeof(frameContext)))
2003                 {
2004                     HANDLE_TRANSIENT_ERROR();
2005                 }
2006
2007                 if (!PAL_VirtualUnwind(&frameContext, NULL))
2008                 {
2009                     HANDLE_TRANSIENT_ERROR();
2010                 }
2011
2012                 fReplyRequired = true;
2013                 pbOptReplyData = (PBYTE)&frameContext;
2014                 cbOptReplyData = sizeof(frameContext);
2015 #endif // RIGHT_SIDE_COMPILE
2016                 break;
2017
2018             case MT_GetDCB:
2019 #ifdef RIGHT_SIDE_COMPILE                
2020                 if (!ProcessReply(&sReceiveHeader))
2021                     HANDLE_TRANSIENT_ERROR();
2022 #else // RIGHT_SIDE_COMPILE
2023                 fReplyRequired = true;
2024                 MarshalDCBToDCBTransport(m_pDCB, &dcbt);
2025                 pbOptReplyData = (PBYTE)&dcbt;
2026                 cbOptReplyData = sizeof(DebuggerIPCControlBlockTransport);
2027 #endif // RIGHT_SIDE_COMPILE
2028                 break;
2029
2030             case MT_SetDCB:
2031 #ifdef RIGHT_SIDE_COMPILE                
2032                 if (!ProcessReply(&sReceiveHeader))
2033                     HANDLE_TRANSIENT_ERROR();
2034 #else // RIGHT_SIDE_COMPILE
2035                 if (sReceiveHeader.m_cbDataBlock != (DWORD)sizeof(DebuggerIPCControlBlockTransport))
2036                 {
2037                     _ASSERTE(!"Inconsistent SetDCB request");
2038                     HANDLE_CRITICAL_ERROR();
2039                 }
2040
2041                 fReplyRequired = true;
2042
2043                 if (!ReceiveBlock((PBYTE)&dcbt, sizeof(DebuggerIPCControlBlockTransport)))
2044                     HANDLE_TRANSIENT_ERROR();
2045
2046                 MarshalDCBTransportToDCB(&dcbt, m_pDCB);
2047 #endif // RIGHT_SIDE_COMPILE
2048                 break;
2049
2050             case MT_GetAppDomainCB:
2051 #ifdef RIGHT_SIDE_COMPILE                
2052                 if (!ProcessReply(&sReceiveHeader))
2053                     HANDLE_TRANSIENT_ERROR();
2054 #else // RIGHT_SIDE_COMPILE
2055                 fReplyRequired = true;
2056                 pbOptReplyData = (PBYTE)m_pADB;
2057                 cbOptReplyData = sizeof(AppDomainEnumerationIPCBlock);
2058 #endif // RIGHT_SIDE_COMPILE
2059                 break;
2060
2061             default:
2062                 _ASSERTE(!"Unknown message type");
2063                 HANDLE_CRITICAL_ERROR();
2064             }
2065
2066 #ifndef RIGHT_SIDE_COMPILE
2067             // On the left side we may need to send a reply back.
2068             if (fReplyRequired)
2069             {
2070                 Message sReply;
2071                 sReply.Init(sReceiveHeader.m_eType, pbOptReplyData, cbOptReplyData);
2072                 sReply.m_sHeader.m_dwReplyId = sReceiveHeader.m_dwId;
2073                 sReply.m_sHeader.TypeSpecificData = sReceiveHeader.TypeSpecificData;
2074
2075 #ifdef _DEBUG
2076                 DbgTransportLog(LC_Requests, "Sending '%s' reply", MessageName(sReceiveHeader.m_eType));
2077 #endif // _DEBUG
2078
2079                 // We must be careful with the failure mode of SendMessage here to avoid the same request
2080                 // being processed too many or too few times. See the comment above starting with 'IMPORTANT
2081                 // NOTE' for more details. The upshot is that on SendMessage hresult failures (which indicate
2082                 // the message will never be sent), we don't update m_dwLastMessageIdSeen and simply wait for
2083                 // the request to be made again. When we get success, however, we must be careful to ensure
2084                 // that m_dwLastMessageIdSeen gets updated even if a network error is reported. Otherwise on
2085                 // the resync we'll both reprocess the request and re-send the original reply which is very
2086                 // very bad.
2087                 hr = SendMessage(&sReply, false);
2088
2089                 if (FAILED(hr))
2090                     HANDLE_TRANSIENT_ERROR(); // Message will never be sent, other side will retry
2091
2092                 // SendMessage doesn't report network errors (it simply queues the send and changes the
2093                 // session state). So check for a network error here specifically so we can get started on the
2094                 // resync. We must update m_dwLastMessageIdSeen first though, or the other side will retry the
2095                 // request.
2096                 if (m_eState != SS_Open)
2097                 {
2098                     _ASSERTE(sReceiveHeader.m_dwId > m_dwLastMessageIdSeen);
2099                     m_dwLastMessageIdSeen = sReceiveHeader.m_dwId;
2100                     HANDLE_TRANSIENT_ERROR();
2101                 }
2102             }
2103 #endif // !RIGHT_SIDE_COMPILE
2104
2105             if (sReceiveHeader.m_dwId != (DWORD)0)
2106             {
2107                 // We've now completed processing on the incoming message. Remember we've processed up to this
2108                 // message ID so that on a resync the other side doesn't send it to us again.
2109                 _ASSERTE(sReceiveHeader.m_dwId > m_dwLastMessageIdSeen);
2110                 m_dwLastMessageIdSeen = sReceiveHeader.m_dwId;
2111             }
2112         }
2113     }
2114
2115   Shutdown:
2116
2117     _ASSERTE(m_eState == SS_Closed);
2118
2119 #ifdef RIGHT_SIDE_COMPILE
2120     // The session is definitely not open at this point.
2121     ResetEvent(m_hSessionOpenEvent);
2122 #endif // RIGHT_SIDE_COMPILE
2123
2124     // Close the connection if we haven't done so already.
2125     m_pipe.Disconnect();
2126
2127     // Drain any remaining entries in the send queue (aborting them when they need completions).
2128     {
2129         TransportLockHolder sLockHolder(&m_sStateLock);
2130
2131         Message *pMsg;
2132         while ((pMsg = m_pSendQueueFirst) != NULL)
2133         {
2134             // Remove message from the queue.
2135             m_pSendQueueFirst = pMsg->m_pNext;
2136
2137             // Determine whether the message needs to be deleted by us before we signal any completion (because
2138             // once we signal the completion pMsg might become invalid immediately if it's not a copy).
2139             bool fMustDelete = pMsg->m_pOrigMessage != pMsg;
2140
2141             // If there's a waiter (i.e. we don't own the message) it know that the operation didn't really
2142             // complete, it was aborted.
2143             if (!fMustDelete)
2144                 pMsg->m_pOrigMessage->m_fAborted = true;
2145
2146             // Determine how to complete the message.
2147             switch (pMsg->m_sHeader.m_eType)
2148             {
2149             case MT_SessionRequest:
2150             case MT_SessionAccept:
2151             case MT_SessionReject:
2152             case MT_SessionResync:
2153             case MT_SessionClose:
2154                 _ASSERTE(!"Session management messages should not be on send queue");
2155                 break;
2156
2157             case MT_Event:
2158                 break;
2159
2160 #ifdef RIGHT_SIDE_COMPILE
2161             case MT_ReadMemory:
2162             case MT_WriteMemory:
2163             case MT_VirtualUnwind:
2164             case MT_GetDCB:
2165             case MT_SetDCB:
2166             case MT_GetAppDomainCB:
2167                 // On the RS these are the original requests. Signal the completion event.
2168                 SignalReplyEvent(pMsg);
2169                 break;
2170 #else // RIGHT_SIDE_COMPILE
2171             case MT_ReadMemory:
2172             case MT_WriteMemory:
2173             case MT_VirtualUnwind:
2174             case MT_GetDCB:
2175             case MT_SetDCB:
2176             case MT_GetAppDomainCB:
2177                 // On the LS these are replies to the original request. Nobody's waiting on these.
2178                 break;
2179 #endif // RIGHT_SIDE_COMPILE
2180
2181             default:
2182                 _ASSERTE(!"Unknown message type");
2183             }
2184
2185             // If the message was a copy, deallocate the resources now.
2186             if (fMustDelete)
2187             {
2188                 if (pMsg->m_pbDataBlock)
2189                     delete [] pMsg->m_pbDataBlock;
2190                 delete pMsg;
2191             }
2192         }
2193     } // Leave m_sStateLock
2194
2195     // Now release all the resources allocated for the transport now that the
2196     // worker thread isn't using them anymore.
2197     Release();
2198 }
2199
2200 // Given a fully initialized debugger event structure, return the size of the structure in bytes (this is not
2201 // trivial since DebuggerIPCEvent contains a large union member which can cause the portion containing
2202 // significant data to vary wildy from event to event).
2203 DWORD DbgTransportSession::GetEventSize(DebuggerIPCEvent *pEvent)
2204 {
2205     DWORD cbBaseSize = offsetof(DebuggerIPCEvent, LeftSideStartupData);
2206     DWORD cbAdditionalSize = 0;
2207
2208     switch (pEvent->type & DB_IPCE_TYPE_MASK)
2209     {
2210     case DB_IPCE_SYNC_COMPLETE:
2211     case DB_IPCE_THREAD_ATTACH:
2212     case DB_IPCE_THREAD_DETACH:
2213     case DB_IPCE_USER_BREAKPOINT:
2214     case DB_IPCE_EXIT_APP_DOMAIN:
2215     case DB_IPCE_SET_DEBUG_STATE_RESULT:
2216     case DB_IPCE_FUNC_EVAL_ABORT_RESULT:
2217     case DB_IPCE_CONTROL_C_EVENT:
2218     case DB_IPCE_FUNC_EVAL_CLEANUP_RESULT:
2219     case DB_IPCE_SET_METHOD_JMC_STATUS_RESULT:
2220     case DB_IPCE_SET_MODULE_JMC_STATUS_RESULT:
2221     case DB_IPCE_FUNC_EVAL_RUDE_ABORT_RESULT:
2222     case DB_IPCE_INTERCEPT_EXCEPTION_RESULT:
2223     case DB_IPCE_INTERCEPT_EXCEPTION_COMPLETE:
2224     case DB_IPCE_CREATE_PROCESS:
2225     case DB_IPCE_SET_NGEN_COMPILER_FLAGS_RESULT:
2226     case DB_IPCE_LEFTSIDE_STARTUP:
2227     case DB_IPCE_ASYNC_BREAK:
2228     case DB_IPCE_CONTINUE:
2229     case DB_IPCE_ATTACHING:
2230     case DB_IPCE_GET_NGEN_COMPILER_FLAGS:
2231     case DB_IPCE_DETACH_FROM_PROCESS:
2232     case DB_IPCE_CONTROL_C_EVENT_RESULT:
2233         cbAdditionalSize = 0;
2234         break;
2235
2236     case DB_IPCE_BREAKPOINT:
2237         cbAdditionalSize = sizeof(pEvent->BreakpointData);
2238         break;
2239
2240     case DB_IPCE_LOAD_MODULE:
2241         cbAdditionalSize = sizeof(pEvent->LoadModuleData);
2242         break;
2243
2244     case DB_IPCE_UNLOAD_MODULE:
2245         cbAdditionalSize = sizeof(pEvent->UnloadModuleData);
2246         break;
2247
2248     case DB_IPCE_LOAD_CLASS:
2249         cbAdditionalSize = sizeof(pEvent->LoadClass);
2250         break;
2251
2252     case DB_IPCE_UNLOAD_CLASS:
2253         cbAdditionalSize = sizeof(pEvent->UnloadClass);
2254         break;
2255
2256     case DB_IPCE_EXCEPTION:
2257         cbAdditionalSize = sizeof(pEvent->Exception);
2258         break;
2259
2260     case DB_IPCE_BREAKPOINT_ADD_RESULT:
2261         cbAdditionalSize = sizeof(pEvent->BreakpointData);
2262         break;
2263
2264     case DB_IPCE_STEP_RESULT:
2265         cbAdditionalSize = sizeof(pEvent->StepData);
2266         if (pEvent->StepData.rangeCount)
2267             cbAdditionalSize += (pEvent->StepData.rangeCount - 1) * sizeof(COR_DEBUG_STEP_RANGE);
2268         break;
2269
2270     case DB_IPCE_STEP_COMPLETE:
2271         cbAdditionalSize = sizeof(pEvent->StepData);
2272         break;
2273
2274     case DB_IPCE_GET_BUFFER_RESULT:
2275         cbAdditionalSize = sizeof(pEvent->GetBufferResult);
2276         break;
2277
2278     case DB_IPCE_RELEASE_BUFFER_RESULT:
2279         cbAdditionalSize = sizeof(pEvent->ReleaseBufferResult);
2280         break;
2281
2282     case DB_IPCE_ENC_ADD_FIELD:
2283         cbAdditionalSize = sizeof(pEvent->EnCUpdate);
2284         break;
2285
2286     case DB_IPCE_APPLY_CHANGES_RESULT:
2287         cbAdditionalSize = sizeof(pEvent->ApplyChangesResult);
2288         break;
2289
2290     case DB_IPCE_FIRST_LOG_MESSAGE:
2291         cbAdditionalSize = sizeof(pEvent->FirstLogMessage);
2292         break;
2293
2294     case DB_IPCE_LOGSWITCH_SET_MESSAGE:
2295         cbAdditionalSize = sizeof(pEvent->LogSwitchSettingMessage);
2296         break;
2297
2298     case DB_IPCE_CREATE_APP_DOMAIN:
2299         cbAdditionalSize = sizeof(pEvent->AppDomainData);
2300         break;
2301
2302     case DB_IPCE_LOAD_ASSEMBLY:
2303         cbAdditionalSize = sizeof(pEvent->AssemblyData);
2304         break;
2305
2306     case DB_IPCE_UNLOAD_ASSEMBLY:
2307         cbAdditionalSize = sizeof(pEvent->AssemblyData);
2308         break;
2309
2310     case DB_IPCE_FUNC_EVAL_SETUP_RESULT:
2311         cbAdditionalSize = sizeof(pEvent->FuncEvalSetupComplete);
2312         break;
2313
2314     case DB_IPCE_FUNC_EVAL_COMPLETE:
2315         cbAdditionalSize = sizeof(pEvent->FuncEvalComplete);
2316         break;
2317
2318     case DB_IPCE_SET_REFERENCE_RESULT:
2319         cbAdditionalSize = sizeof(pEvent->SetReference);
2320         break;
2321
2322     case DB_IPCE_NAME_CHANGE:
2323         cbAdditionalSize = sizeof(pEvent->NameChange);
2324         break;
2325
2326     case DB_IPCE_UPDATE_MODULE_SYMS:
2327         cbAdditionalSize = sizeof(pEvent->UpdateModuleSymsData);
2328         break;
2329
2330     case DB_IPCE_ENC_REMAP:
2331         cbAdditionalSize = sizeof(pEvent->EnCRemap);
2332         break;
2333
2334     case DB_IPCE_SET_VALUE_CLASS_RESULT:
2335         cbAdditionalSize = sizeof(pEvent->SetValueClass);
2336         break;
2337
2338     case DB_IPCE_BREAKPOINT_SET_ERROR:
2339         cbAdditionalSize = sizeof(pEvent->BreakpointSetErrorData);
2340         break;
2341
2342     case DB_IPCE_ENC_UPDATE_FUNCTION:
2343         cbAdditionalSize = sizeof(pEvent->EnCUpdate);
2344         break;
2345
2346     case DB_IPCE_GET_METHOD_JMC_STATUS_RESULT:
2347         cbAdditionalSize = sizeof(pEvent->SetJMCFunctionStatus);
2348         break;
2349
2350     case DB_IPCE_GET_THREAD_FOR_TASKID_RESULT:
2351         cbAdditionalSize = sizeof(pEvent->GetThreadForTaskIdResult);
2352         break;
2353
2354     case DB_IPCE_CREATE_CONNECTION:
2355         cbAdditionalSize = sizeof(pEvent->CreateConnection);
2356         break;
2357
2358     case DB_IPCE_DESTROY_CONNECTION:
2359         cbAdditionalSize = sizeof(pEvent->ConnectionChange);
2360         break;
2361
2362     case DB_IPCE_CHANGE_CONNECTION:
2363         cbAdditionalSize = sizeof(pEvent->ConnectionChange);
2364         break;
2365
2366     case DB_IPCE_EXCEPTION_CALLBACK2:
2367         cbAdditionalSize = sizeof(pEvent->ExceptionCallback2);
2368         break;
2369
2370     case DB_IPCE_EXCEPTION_UNWIND:
2371         cbAdditionalSize = sizeof(pEvent->ExceptionUnwind);
2372         break;
2373
2374     case DB_IPCE_CREATE_HANDLE_RESULT:
2375         cbAdditionalSize = sizeof(pEvent->CreateHandleResult);
2376         break;
2377
2378     case DB_IPCE_ENC_REMAP_COMPLETE:
2379         cbAdditionalSize = sizeof(pEvent->EnCRemapComplete);
2380         break;
2381
2382     case DB_IPCE_ENC_ADD_FUNCTION:
2383         cbAdditionalSize = sizeof(pEvent->EnCUpdate);
2384         break;
2385
2386     case DB_IPCE_GET_NGEN_COMPILER_FLAGS_RESULT:
2387         cbAdditionalSize = sizeof(pEvent->JitDebugInfo);
2388         break;
2389
2390     case DB_IPCE_MDA_NOTIFICATION:
2391         cbAdditionalSize = sizeof(pEvent->MDANotification);
2392         break;
2393
2394     case DB_IPCE_GET_GCHANDLE_INFO_RESULT:
2395         cbAdditionalSize = sizeof(pEvent->GetGCHandleInfoResult);
2396         break;
2397
2398     case DB_IPCE_SET_IP:
2399         cbAdditionalSize = sizeof(pEvent->SetIP);
2400         break;
2401
2402     case DB_IPCE_BREAKPOINT_ADD:
2403         cbAdditionalSize = sizeof(pEvent->BreakpointData);
2404         break;
2405
2406     case DB_IPCE_BREAKPOINT_REMOVE:
2407         cbAdditionalSize = sizeof(pEvent->BreakpointData);
2408         break;
2409
2410     case DB_IPCE_STEP_CANCEL:
2411         cbAdditionalSize = sizeof(pEvent->StepData);
2412         break;
2413
2414     case DB_IPCE_STEP:
2415         cbAdditionalSize = sizeof(pEvent->StepData);
2416         if (pEvent->StepData.rangeCount)
2417             cbAdditionalSize += (pEvent->StepData.rangeCount - 1) * sizeof(COR_DEBUG_STEP_RANGE);
2418         break;
2419
2420     case DB_IPCE_STEP_OUT:
2421         cbAdditionalSize = sizeof(pEvent->StepData);
2422         break;
2423
2424     case DB_IPCE_GET_BUFFER:
2425         cbAdditionalSize = sizeof(pEvent->GetBuffer);
2426         break;
2427
2428     case DB_IPCE_RELEASE_BUFFER:
2429         cbAdditionalSize = sizeof(pEvent->ReleaseBuffer);
2430         break;
2431
2432     case DB_IPCE_SET_CLASS_LOAD_FLAG:
2433         cbAdditionalSize = sizeof(pEvent->SetClassLoad);
2434         break;
2435
2436     case DB_IPCE_APPLY_CHANGES:
2437         cbAdditionalSize = sizeof(pEvent->ApplyChanges);
2438         break;
2439
2440     case DB_IPCE_SET_NGEN_COMPILER_FLAGS:
2441         cbAdditionalSize = sizeof(pEvent->JitDebugInfo);
2442         break;
2443
2444     case DB_IPCE_IS_TRANSITION_STUB:
2445         cbAdditionalSize = sizeof(pEvent->IsTransitionStub);
2446         break;
2447
2448     case DB_IPCE_IS_TRANSITION_STUB_RESULT:
2449         cbAdditionalSize = sizeof(pEvent->IsTransitionStubResult);
2450         break;
2451
2452     case DB_IPCE_MODIFY_LOGSWITCH:
2453         cbAdditionalSize = sizeof(pEvent->LogSwitchSettingMessage);
2454         break;
2455
2456     case DB_IPCE_ENABLE_LOG_MESSAGES:
2457         cbAdditionalSize = sizeof(pEvent->LogSwitchSettingMessage);
2458         break;
2459
2460     case DB_IPCE_FUNC_EVAL:
2461         cbAdditionalSize = sizeof(pEvent->FuncEval);
2462         break;
2463
2464     case DB_IPCE_SET_REFERENCE:
2465         cbAdditionalSize = sizeof(pEvent->SetReference);
2466         break;
2467
2468     case DB_IPCE_FUNC_EVAL_ABORT:
2469         cbAdditionalSize = sizeof(pEvent->FuncEvalAbort);
2470         break;
2471
2472     case DB_IPCE_FUNC_EVAL_CLEANUP:
2473         cbAdditionalSize = sizeof(pEvent->FuncEvalCleanup);
2474         break;
2475
2476     case DB_IPCE_SET_ALL_DEBUG_STATE:
2477         cbAdditionalSize = sizeof(pEvent->SetAllDebugState);
2478         break;
2479
2480     case DB_IPCE_SET_VALUE_CLASS:
2481         cbAdditionalSize = sizeof(pEvent->SetValueClass);
2482         break;
2483
2484     case DB_IPCE_SET_METHOD_JMC_STATUS:
2485         cbAdditionalSize = sizeof(pEvent->SetJMCFunctionStatus);
2486         break;
2487
2488     case DB_IPCE_GET_METHOD_JMC_STATUS:
2489         cbAdditionalSize = sizeof(pEvent->SetJMCFunctionStatus);
2490         break;
2491
2492     case DB_IPCE_SET_MODULE_JMC_STATUS:
2493         cbAdditionalSize = sizeof(pEvent->SetJMCFunctionStatus);
2494         break;
2495
2496     case DB_IPCE_GET_THREAD_FOR_TASKID:
2497         cbAdditionalSize = sizeof(pEvent->GetThreadForTaskId);
2498         break;
2499
2500     case DB_IPCE_FUNC_EVAL_RUDE_ABORT:
2501         cbAdditionalSize = sizeof(pEvent->FuncEvalRudeAbort);
2502         break;
2503
2504     case DB_IPCE_CREATE_HANDLE:
2505         cbAdditionalSize = sizeof(pEvent->CreateHandle);
2506         break;
2507
2508     case DB_IPCE_DISPOSE_HANDLE:
2509         cbAdditionalSize = sizeof(pEvent->DisposeHandle);
2510         break;
2511
2512     case DB_IPCE_INTERCEPT_EXCEPTION:
2513         cbAdditionalSize = sizeof(pEvent->InterceptException);
2514         break;
2515
2516     case DB_IPCE_GET_GCHANDLE_INFO:
2517         cbAdditionalSize = sizeof(pEvent->GetGCHandleInfo);
2518         break;
2519     
2520     case DB_IPCE_CUSTOM_NOTIFICATION:
2521         cbAdditionalSize = sizeof(pEvent->CustomNotification);
2522         break;
2523             
2524     default:
2525         printf("Unknown debugger event type: 0x%x\n", (pEvent->type & DB_IPCE_TYPE_MASK));
2526         _ASSERTE(!"Unknown debugger event type");
2527     }
2528
2529     return cbBaseSize + cbAdditionalSize;
2530 }
2531 #ifdef _PREFAST_
2532 #pragma warning(pop)
2533 #endif
2534
2535 #ifdef _DEBUG
2536 // Debug helper which returns the name associated with a MessageType.
2537 const char *DbgTransportSession::MessageName(MessageType eType)
2538 {
2539     switch (eType)
2540     {
2541     case MT_SessionRequest:
2542         return "SessionRequest";
2543     case MT_SessionAccept:
2544         return "SessionAccept";
2545     case MT_SessionReject:
2546         return "SessionReject";
2547     case MT_SessionResync:
2548         return "SessionResync";
2549     case MT_SessionClose:
2550         return "SessionClose";
2551     case MT_Event:
2552         return "Event";
2553     case MT_ReadMemory:
2554         return "ReadMemory";
2555     case MT_WriteMemory:
2556         return "WriteMemory";
2557     case MT_VirtualUnwind:
2558         return "VirtualUnwind";
2559     case MT_GetDCB:
2560         return "GetDCB";
2561     case MT_SetDCB:
2562         return "SetDCB";
2563     case MT_GetAppDomainCB:
2564         return "GetAppDomainCB";
2565     default:
2566         _ASSERTE(!"Unknown message type");
2567         return NULL;
2568     }
2569 }
2570
2571 // Debug logging helper which logs an incoming message of any type (as long as logging for that message
2572 // class is currently enabled).
2573 void DbgTransportSession::DbgTransportLogMessageReceived(MessageHeader *pHeader)
2574 {
2575     switch (pHeader->m_eType)
2576     {
2577     case MT_SessionRequest:
2578         DbgTransportLog(LC_Session, "Received 'SessionRequest'");
2579         DBG_TRANSPORT_INC_STAT(ReceivedSessionRequest);
2580         return;
2581     case MT_SessionAccept:
2582         DbgTransportLog(LC_Session,  "Received 'SessionAccept'");
2583         DBG_TRANSPORT_INC_STAT(ReceivedSessionAccept);
2584         return;
2585     case MT_SessionReject:
2586         DbgTransportLog(LC_Session,  "Received 'SessionReject'");
2587         DBG_TRANSPORT_INC_STAT(ReceivedSessionReject);
2588         return;
2589     case MT_SessionResync:
2590         DbgTransportLog(LC_Session,  "Received 'SessionResync'");
2591         DBG_TRANSPORT_INC_STAT(ReceivedSessionResync);
2592         return;
2593     case MT_SessionClose:
2594         DbgTransportLog(LC_Session,  "Received 'SessionClose'");
2595         DBG_TRANSPORT_INC_STAT(ReceivedSessionClose);
2596         return;
2597     case MT_Event:
2598         DbgTransportLog(LC_Events,  "Received '%s'",
2599                         IPCENames::GetName((DebuggerIPCEventType)(DWORD)pHeader->TypeSpecificData.Event.m_eType));
2600         DBG_TRANSPORT_INC_STAT(ReceivedEvent);
2601         return;
2602 #ifdef RIGHT_SIDE_COMPILE
2603     case MT_ReadMemory:
2604         DbgTransportLog(LC_Requests,  "Received 'ReadMemory(0x%08X, %u)' reply",
2605                         (PBYTE)pHeader->TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer,
2606                         (DWORD)pHeader->TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer);
2607         DBG_TRANSPORT_INC_STAT(ReceivedReadMemory);
2608         return;
2609     case MT_WriteMemory:
2610         DbgTransportLog(LC_Requests,  "Received 'WriteMemory(0x%08X, %u)' reply",
2611                         (PBYTE)pHeader->TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer,
2612                         (DWORD)pHeader->TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer);
2613         DBG_TRANSPORT_INC_STAT(ReceivedWriteMemory);
2614         return;
2615     case MT_VirtualUnwind:
2616         DbgTransportLog(LC_Requests,  "Received 'VirtualUnwind' reply");
2617         DBG_TRANSPORT_INC_STAT(ReceivedVirtualUnwind);
2618         return;
2619     case MT_GetDCB:
2620         DbgTransportLog(LC_Requests,  "Received 'GetDCB' reply");
2621         DBG_TRANSPORT_INC_STAT(ReceivedGetDCB);
2622         return;
2623     case MT_SetDCB:
2624         DbgTransportLog(LC_Requests,  "Received 'SetDCB' reply");
2625         DBG_TRANSPORT_INC_STAT(ReceivedSetDCB);
2626         return;
2627     case MT_GetAppDomainCB:
2628         DbgTransportLog(LC_Requests,  "Received 'GetAppDomainCB' reply");
2629         DBG_TRANSPORT_INC_STAT(ReceivedGetAppDomainCB);
2630         return;
2631 #else // RIGHT_SIDE_COMPILE
2632     case MT_ReadMemory:
2633         DbgTransportLog(LC_Requests,  "Received 'ReadMemory(0x%08X, %u)'",
2634                         (PBYTE)pHeader->TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer,
2635                         (DWORD)pHeader->TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer);
2636         DBG_TRANSPORT_INC_STAT(ReceivedReadMemory);
2637         return;
2638     case MT_WriteMemory:
2639         DbgTransportLog(LC_Requests,  "Received 'WriteMemory(0x%08X, %u)'",
2640                         (PBYTE)pHeader->TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer,
2641                         (DWORD)pHeader->TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer);
2642         DBG_TRANSPORT_INC_STAT(ReceivedWriteMemory);
2643         return;
2644     case MT_VirtualUnwind:
2645         DbgTransportLog(LC_Requests,  "Received 'VirtualUnwind'");
2646         DBG_TRANSPORT_INC_STAT(ReceivedVirtualUnwind);
2647         return;
2648     case MT_GetDCB:
2649         DbgTransportLog(LC_Requests,  "Received 'GetDCB'");
2650         DBG_TRANSPORT_INC_STAT(ReceivedGetDCB);
2651         return;
2652     case MT_SetDCB:
2653         DbgTransportLog(LC_Requests,  "Received 'SetDCB'");
2654         DBG_TRANSPORT_INC_STAT(ReceivedSetDCB);
2655         return;
2656     case MT_GetAppDomainCB:
2657         DbgTransportLog(LC_Requests,  "Received 'GetAppDomainCB'");
2658         DBG_TRANSPORT_INC_STAT(ReceivedGetAppDomainCB);
2659         return;
2660 #endif // RIGHT_SIDE_COMPILE
2661     default:
2662         _ASSERTE(!"Unknown message type");
2663         return;
2664     }
2665 }
2666
2667 static CLRRandom s_faultInjectionRandom;
2668
2669 // Helper method used by the DBG_TRANSPORT_SHOULD_INJECT_FAULT macro.
2670 bool DbgTransportSession::DbgTransportShouldInjectFault(DbgTransportFaultOp eOp, const char *szOpName)
2671 {
2672     static DWORD s_dwFaultInjection = 0xffffffff;
2673
2674     // Init the fault injection system if that hasn't already happened.
2675     if (s_dwFaultInjection == 0xffffffff)
2676     {
2677         s_dwFaultInjection = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgTransportFaultInject);
2678
2679         // Try for repeatable failures here by always initializing the random seed to a fixed value. But use
2680         // different seeds for the left and right sides or they'll end up in lock step. The
2681         // DBG_TRANSPORT_FAULT_THIS_SIDE macro is a convenient integer value that differs on each side.
2682         s_faultInjectionRandom.Init(DBG_TRANSPORT_FAULT_THIS_SIDE);
2683
2684         // Clamp failure rate to a permissable value.
2685         if ((s_dwFaultInjection & DBG_TRANSPORT_FAULT_RATE_MASK) > 99)
2686             s_dwFaultInjection = (s_dwFaultInjection & ~DBG_TRANSPORT_FAULT_RATE_MASK) | 99;
2687     }
2688
2689     // Map current session state into the bitmask format used for fault injection control.
2690     DWORD dwState = 0;
2691     switch (m_eState)
2692     {
2693     case SS_Opening_NC:
2694     case SS_Opening:
2695         dwState = FS_Opening;
2696         break;
2697     case SS_Resync_NC:
2698     case SS_Resync:
2699         dwState = FS_Resync;
2700         break;
2701     case SS_Open:
2702         dwState = FS_Open;
2703         break;
2704     case SS_Closed:
2705         break;
2706     default:
2707         _ASSERTE(!"Bad session state");
2708     }
2709
2710     if ((s_dwFaultInjection & DBG_TRANSPORT_FAULT_THIS_SIDE) &&
2711         (s_dwFaultInjection & eOp) &&
2712         (s_dwFaultInjection & dwState))
2713     {
2714         // We're faulting this side, op and state. Roll the dice and see if this particular call should fail.
2715         DWORD dwChance = s_faultInjectionRandom.Next(100);
2716         if (dwChance < (s_dwFaultInjection & DBG_TRANSPORT_FAULT_RATE_MASK))
2717         {
2718             DbgTransportLog(LC_FaultInject, "Injected fault for %s operation", szOpName);
2719 #if defined(FEATURE_CORESYSTEM)
2720         // not supported
2721 #else
2722             WSASetLastError(WSAEFAULT);
2723 #endif // defined(FEATURE_CORESYSTEM)
2724             return true;
2725         }
2726     }
2727
2728     return false;
2729 }
2730 #endif // _DEBUG
2731
2732 // Lock abstraction code (hides difference in lock implementation between left and right side).
2733 #ifdef RIGHT_SIDE_COMPILE
2734
2735 // On the right side we use a CRITICAL_SECTION.
2736
2737 void DbgTransportLock::Init()
2738 {
2739     InitializeCriticalSection(&m_sLock);
2740 }
2741
2742 void DbgTransportLock::Destroy()
2743 {
2744     DeleteCriticalSection(&m_sLock);
2745 }
2746
2747 void DbgTransportLock::Enter()
2748 {
2749     EnterCriticalSection(&m_sLock);
2750 }
2751
2752 void DbgTransportLock::Leave()
2753 {
2754     LeaveCriticalSection(&m_sLock);
2755 }
2756 #else // RIGHT_SIDE_COMPILE
2757
2758 // On the left side we use a Crst.
2759
2760 void DbgTransportLock::Init()
2761 {
2762     m_sLock.Init(CrstDbgTransport, (CrstFlags)(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
2763 }
2764
2765 void DbgTransportLock::Destroy()
2766 {
2767 }
2768
2769 void DbgTransportLock::Enter()
2770 {
2771     m_sLock.Enter();
2772 }
2773
2774 void DbgTransportLock::Leave()
2775 {
2776     m_sLock.Leave();
2777 }
2778 #endif // RIGHT_SIDE_COMPILE
2779
2780 #endif // (!defined(RIGHT_SIDE_COMPILE) && defined(FEATURE_DBGIPC_TRANSPORT_VM)) || (defined(RIGHT_SIDE_COMPILE) && defined(FEATURE_DBGIPC_TRANSPORT_DI))