text: /*
   * $Header$
   *
   * Copyright 2008 Massachusetts Institute of Technology.
   * All Rights Reserved.
   *
   * Export of this software from the United States of America may
   * require a specific license from the United States Government.
   * It is the responsibility of any person or organization contemplating
   * export to obtain such a license before exporting.
   *
   * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
   * distribute this software and its documentation for any purpose and
   * without fee is hereby granted, provided that the above copyright
   * notice appear in all copies and that both that copyright notice and
   * this permission notice appear in supporting documentation, and that
   * the name of M.I.T. not be used in advertising or publicity pertaining
   * to distribution of the software without specific, written prior
   * permission.  Furthermore if you modify this software you must label
   * your software as modified software and not distribute it in such a
   * fashion that it might be confused with the original M.I.T. software.
   * M.I.T. makes no representations about the suitability of
   * this software for any purpose.  It is provided "as is" without express
   * or implied warranty.
   */
  
  extern "C" {
  #include <windows.h>
  #include <LMCons.h>
  
  #include "dllmain.h"
  #include "tls.h"
  #include "cci_debugging.h"
  #include "ccapi_context.h"
  #include "ccapi_ipc.h"
  #include "client.h"
  
  void cci_process_init__auxinit();
      }
  
  
  #define CCAPI_V2_MUTEX_NAME     TEXT("MIT_CCAPI_V4_MUTEX")
  
  // Process-specific data:
  static DWORD    dwTlsIndex;
  static char     _user[UNLEN+1];     // Username is used as part of the server and client endpoints.
  static  HANDLE  sessionToken;
  static char*    ep_prefices[]   = {"CCS", "CCAPI"};
  HANDLE          hCCAPIv2Mutex   = NULL;
  DWORD           firstThreadID   = 0;
  
  // These data structures are used by the old CCAPI implementation 
  //  to keep track of the state of the RPC connection.  All data is static.
  static Init     init;
  static Client   client;
  
  DWORD    GetTlsIndex()  {return dwTlsIndex;}
  
  // DllMain() is the entry-point function for this DLL. 
  BOOL WINAPI DllMain(HINSTANCE hinstDLL,     // DLL module handle
                      DWORD fdwReason,        // reason called
                      LPVOID lpvReserved) {   // reserved 
  
      struct tspdata* ptspdata;
      BOOL            fIgnore;
      BOOL            bStatus;
      DWORD           status      = 0;        // 0 is success.
      DWORD           maxUN       = sizeof(_user);
      unsigned int    i           = 0;
      unsigned int    j           = 0;
   
      switch (fdwReason) { 
          // The DLL is loading due to process initialization or a call to LoadLibrary:
          case DLL_PROCESS_ATTACH: 
              cci_debug_printf("%s DLL_PROCESS_ATTACH", __FUNCTION__);
              // Process-wide mutex used to allow only one thread at a time into the RPC code:
              hCCAPIv2Mutex = CreateMutex(NULL, FALSE, CCAPI_V2_MUTEX_NAME);
  
              // Figure out our username; it's process-wide:
              bStatus = GetUserName(_user, &maxUN);
              if (!bStatus) return bStatus;
  
              // Remove any characters that aren't valid endpoint characters:
              while (_user[j] != 0) {
                  if (isalnum(_user[j])) _user[i++] = _user[j];
                  j++;
                  }
              _user[i]    = '\0';
  
              // Our logon session is determined in client.cxx, old CCAPI code carried
              //  over to this implementation.
  
              // Allocate a TLS index:
              if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE; 
  
              cci_process_init__auxinit();
              // Don't break; fallthrough: Initialize the TLS index for first thread.
   
          // The attached process creates a new thread:
          case DLL_THREAD_ATTACH:
              cci_debug_printf("%s DLL_THREAD_ATTACH", __FUNCTION__);
              // Don't actually rely on this case for allocation of resources.
              // Applications (like SecureCRT) may have threads already
              // created (say 'A' and 'B') before the dll is loaded. If the dll
              // is loaded in thread 'A' but then used in thread 'B', thread 'B'
              // will never execute this code.
              fIgnore     = TlsSetValue(dwTlsIndex, NULL);
  
              // Do not call cci_ipc_thread_init() yet; defer until we actually
              // need it.  On XP, cci_ipc_thread_init() will cause additional
              // threads to be immediately spawned, which will bring us right
              // back here again ad infinitum, until windows
              // resources are exhausted.
              break;
   
          // The thread of the attached process terminates:
          case DLL_THREAD_DETACH: 
              cci_debug_printf("%s DLL_THREAD_DETACH", __FUNCTION__);
              // Release the allocated memory for this thread
              ptspdata = (struct tspdata*)TlsGetValue(dwTlsIndex); 
              if (ptspdata != NULL) {
                  free(ptspdata);
                  TlsSetValue(dwTlsIndex, NULL); 
                  }
              break; 
   
          // DLL unload due to process termination or FreeLibrary:
          case DLL_PROCESS_DETACH: 
              cci_debug_printf("%s DLL_PROCESS_DETACH", __FUNCTION__);
              //++ Copied from previous implementation:
              // Process Teardown "Problem"
              //
              // There are two problems that occur during process teardown:
              //
              // 1) Windows (NT/9x/2000) does not keep track of load/unload
              //    ordering dependencies for use in process teardown.
              //
              // 2) The RPC exception handling in the RPC calls do not work
              //    during process shutdown in Win9x.
              //
              // When a process is being torn down in Windows, the krbcc DLL
              // may get a DLL_PROCESS_DETACH before other DLLs are done
              // with it.  Thus, it may disconnect from the RPC server
              // before the last shutdown RPC call.
              //
              // On NT/2000, this is ok because the RPC call will fail and just
              // return an error.
              //
              // On Win9x/Me, the RPC exception will not be caught.
              // However, Win9x ignores exceptions during process shutdown,
              // so the exception will never be seen unless a debugger is
              // attached to the proccess.
              //
              // A good potential woraround would be to have a global
              // variable that denotes whether the DLL is attached to the
              // process.  If it is not, all entrypoints into the DLL should
              // return failure.
              //
              // A not as good workaround is below but ifdefed out.
              //
              // However, we can safely ignore this problem since it can
              // only affects people running debuggers under 9x/Me who are
              // using multiple DLLs that use this DLL.
              //
              WaitForSingleObject( hCCAPIv2Mutex, INFINITE );
  #if 0
              bool process_teardown_workaround = false;
              if (lpvReserved) {
                  Init::InitInfo info;
                  status = Init::Info(info);
                  if (status) break;
                  if (!info.isNT) process_teardown_workaround = true;
              }
              if (process_teardown_workaround)
                  break;
  #endif
              // return value is ignored, so we set status for debugging purposes
              status = Client::Cleanup();
              status = Init::Cleanup();
              ReleaseMutex( hCCAPIv2Mutex );
              CloseHandle( hCCAPIv2Mutex );
              //-- Copied from previous implementation.
  
              // Release the allocated memory for this thread:
              ptspdata = (struct tspdata*)TlsGetValue(dwTlsIndex); 
              if (ptspdata != NULL)
                  free(ptspdata);
              TlsFree(dwTlsIndex);    // Release the TLS index.
              // Ideally, we would enumerate all other threads here and
              // release their thread local storage as well.
              break; 
   
          default:
              cci_debug_printf("%s unexpected reason %d", __FUNCTION__, fdwReason);
              break;
          } 
   
      UNREFERENCED_PARAMETER(hinstDLL);       // no whining!
      UNREFERENCED_PARAMETER(lpvReserved); 
      return status ? FALSE : TRUE;
  }
  
  
  #ifdef __cplusplus    // If used by C++ code, 
  extern "C" {          // we need to export the C interface
  #endif
  
  #ifdef __cplusplus
  }
  #endif
  
  /*********************************************************************/
  /*                 MIDL allocate and free                            */
  /*********************************************************************/
  
  extern "C" void  __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len) {
      return(malloc(len));
      }
  
  extern "C" void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) {
      free(ptr);
      }
  