Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
ipcdWin.cpp File Reference
#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"

Go to the source code of this file.

Defines

#define IPC_PURGE_TIMER_ID   1
#define IPC_WM_SENDMSG   (WM_USER + 1)
#define IPC_WM_SHUTDOWN   (WM_USER + 2)

Functions

static void RemoveClient (ipcClient *client)
static void PurgeStaleClients ()
static ipcClientAddClient (HWND hwnd, PRUint32 pid)
static ipcClientGetClientByPID (PRUint32 pid)
static void ProcessMsg (HWND hwnd, PRUint32 pid, const ipcMessage *msg)
PRStatus IPC_PlatformSendMsg (ipcClient *client, ipcMessage *msg)
static LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static PRBool AcquireLock ()
static void ReleaseLock ()
int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int)

Variables

ipcClientipcClients = NULL
int ipcClientCount = 0
static ipcClient ipcClientArray [IPC_MAX_CLIENTS]
static HWND ipcHwnd = NULL
static PRBool ipcShutdown = PR_FALSE
static HANDLE ipcSyncEvent

Define Documentation

Definition at line 62 of file ipcdWin.cpp.

#define IPC_WM_SENDMSG   (WM_USER + 1)

Definition at line 63 of file ipcdWin.cpp.

#define IPC_WM_SHUTDOWN   (WM_USER + 2)

Definition at line 64 of file ipcdWin.cpp.


Function Documentation

static PRBool AcquireLock ( ) [static]

Definition at line 304 of file ipcdWin.cpp.

{
    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;
}

Here is the caller graph for this function:

static ipcClient* AddClient ( HWND  hwnd,
PRUint32  pid 
) [static]

Definition at line 131 of file ipcdWin.cpp.

{
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static ipcClient* GetClientByPID ( PRUint32  pid) [static]

Definition at line 161 of file ipcdWin.cpp.

{
    for (int i=0; i<ipcClientCount; ++i) {
        if (ipcClientArray[i].PID() == pid)
            return &ipcClientArray[i];
    }
    return NULL;
}

Here is the caller graph for this function:

PRStatus IPC_PlatformSendMsg ( ipcClient client,
ipcMessage msg 
)

Definition at line 205 of file ipcdWin.cpp.

{
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ProcessMsg ( HWND  hwnd,
PRUint32  pid,
const ipcMessage msg 
) [static]

Definition at line 175 of file ipcdWin.cpp.

{
    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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PurgeStaleClients ( ) [static]

Definition at line 101 of file ipcdWin.cpp.

{
    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);
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ReleaseLock ( ) [static]

Definition at line 324 of file ipcdWin.cpp.

{
    if (ipcSyncEvent) {
        LOG(("releasing lock...\n"));
        CloseHandle(ipcSyncEvent);
        ipcSyncEvent = NULL;
    }
}

Here is the caller graph for this function:

static void RemoveClient ( ipcClient client) [static]

Definition at line 71 of file ipcdWin.cpp.

{
    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;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static LRESULT CALLBACK WindowProc ( HWND  hWnd,
UINT  uMsg,
WPARAM  wParam,
LPARAM  lParam 
) [static]

Definition at line 228 of file ipcdWin.cpp.

{
    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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int WINAPI WinMain ( HINSTANCE  ,
HINSTANCE  ,
LPSTR  ,
int   
)

Definition at line 341 of file ipcdWin.cpp.

{
    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;
}

Here is the call graph for this function:


Variable Documentation

Definition at line 57 of file ipcdWin.cpp.

Definition at line 55 of file ipcdWin.cpp.

Definition at line 54 of file ipcdWin.cpp.

HWND ipcHwnd = NULL [static]

Definition at line 59 of file ipcdWin.cpp.

Definition at line 60 of file ipcdWin.cpp.

HANDLE ipcSyncEvent [static]

Definition at line 301 of file ipcdWin.cpp.