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