1 /*
   2  * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef _SERVER_LISTS_
  26 #define _SERVER_LISTS_
  27 
  28 #include <vector>
  29 #include <winsock2.h>
  30 #include "IOBuf.hpp"
  31 
  32 //
  33 // NOTE:
  34 //
  35 // All of these lists are guarded by the global lock managed by the
  36 // Lists class. Lists::init() must be called at the start of the
  37 // program.
  38 //
  39 
  40 class Lists {
  41   friend class ListsLocker;
  42 public:
  43   static void init();
  44 private:
  45   static void lock();
  46   static void unlock();
  47   static CRITICAL_SECTION crit;
  48 };
  49 
  50 // Should be allocated on stack. Ensures proper locking/unlocking
  51 // pairing.
  52 class ListsLocker {
  53 public:
  54   ListsLocker();
  55   ~ListsLocker();
  56 };
  57 
  58 // We must keep track of all of the child processes we have forked to
  59 // handle attaching to a target process. This is necessary because we
  60 // allow clients to detach from processes, but the child processes we
  61 // fork must necessarily stay alive for the duration of the target
  62 // application. A subsequent attach operation to the target process
  63 // results in the same child process being reused. For this reason,
  64 // child processes are known to be in one of two states: attached and
  65 // detached.
  66 
  67 class ClientInfo;
  68 
  69 class ChildInfo {
  70 public:
  71   /** The pid of the ChildInfo indicates the process ID of the target
  72       process which the subprocess was created to debug, not the pid
  73       of the subprocess itself. */
  74   ChildInfo(DWORD pid, HANDLE childProcessHandle,
  75             HANDLE writeToStdinHandle, HANDLE readFromStdoutHandle,
  76             HANDLE auxHandle1, HANDLE auxHandle2);
  77 
  78   DWORD getPid();
  79   HANDLE getChildProcessHandle();
  80   HANDLE getWriteToStdinHandle();
  81   HANDLE getReadFromStdoutHandle();
  82 
  83   /** Set the client which is currently attached to the target process
  84       via this child process. Set this to NULL to indicate that the
  85       child process is ready to accept another attachment. */
  86   void setClient(ClientInfo* clientInfo);
  87 
  88   ClientInfo* getClient();
  89 
  90   /** This is NOT automatically called in the destructor */
  91   void closeAll();
  92 
  93 private:
  94   DWORD pid;
  95   HANDLE childProcessHandle;
  96   HANDLE writeToStdinHandle;
  97   HANDLE readFromStdoutHandle;
  98   HANDLE auxHandle1;
  99   HANDLE auxHandle2;
 100   ClientInfo* client;
 101 };
 102 
 103 // We keep track of a list of child debugger processes, each of which
 104 // is responsible for debugging a certain target process. These
 105 // debugger processes can serve multiple clients during their
 106 // lifetime. When a client detaches from a given process or tells the
 107 // debugger to "exit", the debug server is notified that the child
 108 // process is once again available to accept connections from clients.
 109 
 110 class ChildList {
 111 private:
 112   typedef std::vector<ChildInfo*> ChildInfoList;
 113 
 114 public:
 115   ChildList();
 116   ~ChildList();
 117 
 118   void addChild(ChildInfo*);
 119 
 120   /** Removes and returns the ChildInfo* associated with the given
 121       child process handle. */
 122   ChildInfo* removeChild(HANDLE childProcessHandle);
 123 
 124   /** Removes the given ChildInfo. */
 125   void removeChild(ChildInfo* info);
 126 
 127   /** Return the ChildInfo* associated with a given process ID without
 128       removing it from the list. */
 129   ChildInfo* getChildByPid(DWORD pid);
 130 
 131   /** Iteration support */
 132   int size();
 133 
 134   /** Iteration support */
 135   ChildInfo* getChildByIndex(int index);
 136 
 137 private:
 138   ChildInfoList childList;
 139 };
 140 
 141 // We also keep a list of clients whose requests we are responsible
 142 // for serving. Clients can attach and detach from child processes.
 143 
 144 class ClientInfo {
 145 public:
 146   ClientInfo(SOCKET dataSocket);
 147   ~ClientInfo();
 148 
 149   SOCKET getDataSocket();
 150   /** Gets an IOBuf configured for the data socket, which should be
 151       used for all communication with the client. */
 152   IOBuf* getIOBuf();
 153 
 154   /** Set the information for the process to which this client is
 155       attached. Set this to NULL to indicate that the client is not
 156       currently attached to any target process. */
 157   void setTarget(ChildInfo* childInfo);
 158 
 159   /** Get the information for the process to which this client is
 160       currently attached, or NULL if none. */
 161   ChildInfo* getTarget();
 162 
 163   /** Close down the socket connection to this client. This is NOT
 164       automatically called by the destructor. */
 165   void closeAll();
 166 
 167 private:
 168   SOCKET dataSocket;
 169   IOBuf* buf;
 170   ChildInfo* target;
 171 };
 172 
 173 class ClientList {
 174 private:
 175   typedef std::vector<ClientInfo*> ClientInfoList;
 176 
 177 public:
 178   ClientList();
 179   ~ClientList();
 180 
 181   /** Adds a client to the list. */
 182   void addClient(ClientInfo* info);
 183 
 184   /** Check to see whether the parent socket of any of the ClientInfo
 185       objects is readable in the given fd_set. If so, returns TRUE and
 186       sets the given ClientInfo* (a non-NULL pointer to which must be
 187       given) appropriately. */
 188   bool isAnyDataSocketSet(fd_set* fds, ClientInfo** info);
 189 
 190   /** Removes a client from the list. User is responsible for deleting
 191       the ClientInfo* using operator delete. */
 192   void removeClient(ClientInfo* client);
 193 
 194   /** Iteration support. */
 195   int size();
 196 
 197   /** Iteration support. */
 198   ClientInfo* get(int num);
 199 
 200 private:
 201   ClientInfoList clientList;
 202 };
 203 
 204 #endif  // #defined _SERVER_LISTS_