summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp')
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp408
1 files changed, 408 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp
new file mode 100644
index 00000000..f89fba06
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp
@@ -0,0 +1,408 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <windows.h>
+
+#include "prthread.h"
+
+#include "ipcConfig.h"
+#include "ipcLog.h"
+#include "ipcMessage.h"
+#include "ipcClient.h"
+#include "ipcModuleReg.h"
+#include "ipcdPrivate.h"
+#include "ipcd.h"
+#include "ipcm.h"
+
+//
+// declared in ipcdPrivate.h
+//
+ipcClient *ipcClients = NULL;
+int ipcClientCount = 0;
+
+static ipcClient ipcClientArray[IPC_MAX_CLIENTS];
+
+static HWND ipcHwnd = NULL;
+static PRBool ipcShutdown = PR_FALSE;
+
+#define IPC_PURGE_TIMER_ID 1
+#define IPC_WM_SENDMSG (WM_USER + 1)
+#define IPC_WM_SHUTDOWN (WM_USER + 2)
+
+//-----------------------------------------------------------------------------
+// client array manipulation
+//-----------------------------------------------------------------------------
+
+static void
+RemoveClient(ipcClient *client)
+{
+ LOG(("RemoveClient\n"));
+
+ int clientIndex = client - ipcClientArray;
+
+ client->Finalize();
+
+ //
+ // move last ipcClient object down into the spot occupied by this client.
+ //
+ int fromIndex = ipcClientCount - 1;
+ int toIndex = clientIndex;
+ if (toIndex != fromIndex)
+ memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient));
+
+ memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient));
+
+ --ipcClientCount;
+ LOG((" num clients = %u\n", ipcClientCount));
+
+ if (ipcClientCount == 0) {
+ LOG((" shutting down...\n"));
+ KillTimer(ipcHwnd, IPC_PURGE_TIMER_ID);
+ PostQuitMessage(0);
+ ipcShutdown = PR_TRUE;
+ }
+}
+
+static void
+PurgeStaleClients()
+{
+ if (ipcClientCount == 0)
+ return;
+
+ LOG(("PurgeStaleClients [num-clients=%u]\n", ipcClientCount));
+ //
+ // walk the list of supposedly active clients, and verify the existance of
+ // their respective message windows.
+ //
+ char wName[IPC_CLIENT_WINDOW_NAME_MAXLEN];
+ for (int i=ipcClientCount-1; i>=0; --i) {
+ ipcClient *client = &ipcClientArray[i];
+
+ LOG((" checking client at index %u [client-id=%u pid=%u]\n",
+ i, client->ID(), client->PID()));
+
+ IPC_GetClientWindowName(client->PID(), wName);
+
+ // XXX dougt has ideas about how to make this better
+
+ HWND hwnd = FindWindow(IPC_CLIENT_WINDOW_CLASS, wName);
+ if (!hwnd) {
+ LOG((" client window not found; removing client!\n"));
+ RemoveClient(client);
+ }
+ }
+}
+
+static ipcClient *
+AddClient(HWND hwnd, PRUint32 pid)
+{
+ LOG(("AddClient\n"));
+
+ //
+ // before adding a new client, verify that all existing clients are
+ // still up and running. remove any stale clients.
+ //
+ PurgeStaleClients();
+
+ if (ipcClientCount == IPC_MAX_CLIENTS) {
+ LOG((" reached maximum client count!\n"));
+ return NULL;
+ }
+
+ ipcClient *client = &ipcClientArray[ipcClientCount];
+ client->Init();
+ client->SetHwnd(hwnd);
+ client->SetPID(pid); // XXX one function instead of 3
+
+ ++ipcClientCount;
+ LOG((" num clients = %u\n", ipcClientCount));
+
+ if (ipcClientCount == 1)
+ SetTimer(ipcHwnd, IPC_PURGE_TIMER_ID, 1000, NULL);
+
+ return client;
+}
+
+static ipcClient *
+GetClientByPID(PRUint32 pid)
+{
+ for (int i=0; i<ipcClientCount; ++i) {
+ if (ipcClientArray[i].PID() == pid)
+ return &ipcClientArray[i];
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// message processing
+//-----------------------------------------------------------------------------
+
+static void
+ProcessMsg(HWND hwnd, PRUint32 pid, const ipcMessage *msg)
+{
+ LOG(("ProcessMsg [pid=%u len=%u]\n", pid, msg->MsgLen()));
+
+ ipcClient *client = GetClientByPID(pid);
+
+ if (client) {
+ //
+ // if this is an IPCM "client hello" message, then reset the client
+ // instance object.
+ //
+ if (msg->Target().Equals(IPCM_TARGET) &&
+ IPCM_GetType(msg) == IPCM_MSG_REQ_CLIENT_HELLO) {
+ RemoveClient(client);
+ client = NULL;
+ }
+ }
+
+ if (client == NULL) {
+ client = AddClient(hwnd, pid);
+ if (!client)
+ return;
+ }
+
+ IPC_DispatchMsg(client, msg);
+}
+
+//-----------------------------------------------------------------------------
+
+PRStatus
+IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg)
+{
+ LOG(("IPC_PlatformSendMsg [clientID=%u clientPID=%u]\n",
+ client->ID(), client->PID()));
+
+ // use PostMessage to make this asynchronous; otherwise we might get
+ // some wierd SendMessage recursion between processes.
+
+ WPARAM wParam = (WPARAM) client->Hwnd();
+ LPARAM lParam = (LPARAM) msg;
+ if (!PostMessage(ipcHwnd, IPC_WM_SENDMSG, wParam, lParam)) {
+ LOG(("PostMessage failed\n"));
+ delete msg;
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// windows message loop
+//-----------------------------------------------------------------------------
+
+static LRESULT CALLBACK
+WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam));
+
+ if (uMsg == WM_COPYDATA) {
+ if (ipcShutdown) {
+ LOG(("ignoring message b/c daemon is shutting down\n"));
+ return TRUE;
+ }
+ COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam;
+ if (cd && cd->lpData) {
+ ipcMessage msg;
+ PRUint32 bytesRead;
+ PRBool complete;
+ // XXX avoid extra malloc
+ PRStatus rv = msg.ReadFrom((const char *) cd->lpData, cd->cbData,
+ &bytesRead, &complete);
+ if (rv == PR_SUCCESS && complete) {
+ //
+ // grab client PID and hwnd.
+ //
+ ProcessMsg((HWND) wParam, (PRUint32) cd->dwData, &msg);
+ }
+ else
+ LOG(("ignoring malformed message\n"));
+ }
+ return TRUE;
+ }
+
+ if (uMsg == IPC_WM_SENDMSG) {
+ HWND hWndDest = (HWND) wParam;
+ ipcMessage *msg = (ipcMessage *) lParam;
+
+ COPYDATASTRUCT cd;
+ cd.dwData = GetCurrentProcessId();
+ cd.cbData = (DWORD) msg->MsgLen();
+ cd.lpData = (PVOID) msg->MsgBuf();
+
+ LOG(("calling SendMessage...\n"));
+ SendMessage(hWndDest, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd);
+ LOG((" done.\n"));
+
+ delete msg;
+ return 0;
+ }
+
+ if (uMsg == WM_TIMER) {
+ PurgeStaleClients();
+ return 0;
+ }
+
+#if 0
+ if (uMsg == IPC_WM_SHUTDOWN) {
+ //
+ // since this message is handled asynchronously, it is possible
+ // that other clients may have come online since this was issued.
+ // in which case, we need to ignore this message.
+ //
+ if (ipcClientCount == 0) {
+ ipcShutdown = PR_TRUE;
+ PostQuitMessage(0);
+ }
+ return 0;
+ }
+#endif
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+//-----------------------------------------------------------------------------
+// daemon startup synchronization
+//-----------------------------------------------------------------------------
+
+static HANDLE ipcSyncEvent;
+
+static PRBool
+AcquireLock()
+{
+ ipcSyncEvent = CreateEvent(NULL, FALSE, FALSE,
+ IPC_SYNC_EVENT_NAME);
+ if (!ipcSyncEvent) {
+ LOG(("CreateEvent failed [%u]\n", GetLastError()));
+ return PR_FALSE;
+ }
+
+ // check to see if event already existed prior to this call.
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ LOG((" lock already set; exiting...\n"));
+ return PR_FALSE;
+ }
+
+ LOG((" acquired lock\n"));
+ return PR_TRUE;
+}
+
+static void
+ReleaseLock()
+{
+ if (ipcSyncEvent) {
+ LOG(("releasing lock...\n"));
+ CloseHandle(ipcSyncEvent);
+ ipcSyncEvent = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// main
+//-----------------------------------------------------------------------------
+
+#ifdef DEBUG
+int
+main()
+#else
+int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+#endif
+{
+ IPC_InitLog("###");
+
+ LOG(("daemon started...\n"));
+
+ if (!AcquireLock()) {
+ // unblock the parent; it should be able to find the IPC window of the
+ // other daemon process.
+ IPC_NotifyParent();
+ return 0;
+ }
+
+ // initialize global data
+ memset(ipcClientArray, 0, sizeof(ipcClientArray));
+ ipcClients = ipcClientArray;
+ ipcClientCount = 0;
+
+ // create message window up front...
+ WNDCLASS wc;
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.lpszClassName = IPC_WINDOW_CLASS;
+
+ RegisterClass(&wc);
+
+ ipcHwnd = CreateWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME,
+ 0, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
+
+ // unblock the parent process; it should now look for the IPC window.
+ IPC_NotifyParent();
+
+ if (!ipcHwnd)
+ return -1;
+
+ // load modules relative to the location of the executable...
+ {
+ char path[MAX_PATH];
+ GetModuleFileName(NULL, path, sizeof(path));
+ IPC_InitModuleReg(path);
+ }
+
+ LOG(("entering message loop...\n"));
+ MSG msg;
+ while (GetMessage(&msg, ipcHwnd, 0, 0))
+ DispatchMessage(&msg);
+
+ // unload modules
+ IPC_ShutdownModuleReg();
+
+ //
+ // we release the daemon lock before destroying the window because the
+ // absence of our window is what will cause clients to try to spawn the
+ // daemon.
+ //
+ ReleaseLock();
+
+ //LOG(("sleeping 5 seconds...\n"));
+ //PR_Sleep(PR_SecondsToInterval(5));
+
+ LOG(("destroying message window...\n"));
+ DestroyWindow(ipcHwnd);
+ ipcHwnd = NULL;
+
+ LOG(("exiting\n"));
+ return 0;
+}