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