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