189 lines
6.7 KiB
C++
189 lines
6.7 KiB
C++
|
/*
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_START@
|
||
|
*
|
||
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||
|
*
|
||
|
* This file contains Original Code and/or Modifications of Original Code
|
||
|
* as defined in and that are subject to the Apple Public Source License
|
||
|
* Version 2.0 (the 'License'). You may not use this file except in
|
||
|
* compliance with the License. Please obtain a copy of the License at
|
||
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||
|
* file.
|
||
|
*
|
||
|
* The Original Code and all software distributed under the License are
|
||
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||
|
* Please see the License for the specific language governing rights and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* @APPLE_LICENSE_HEADER_END@
|
||
|
*
|
||
|
*/
|
||
|
/*
|
||
|
File: win32ev.cpp
|
||
|
|
||
|
Contains: WSA implementation of socket event queue functions.
|
||
|
|
||
|
Written By: Denis Serenyi
|
||
|
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "ev.h"
|
||
|
#include "OSHeaders.h"
|
||
|
#include "OSThread.h"
|
||
|
#include "MyAssert.h"
|
||
|
|
||
|
//
|
||
|
// You have to create a window to get socket events? What's up with that?
|
||
|
static HWND sMsgWindow = NULL;
|
||
|
|
||
|
//
|
||
|
LRESULT CALLBACK select_wndproc(HWND inWIndow, UINT inMsg, WPARAM inParam, LPARAM inOtherParam);
|
||
|
|
||
|
void select_startevents()
|
||
|
{
|
||
|
//
|
||
|
// This call occurs from the main thread. In Win32, apparently, you
|
||
|
// have to create your WSA window from the same thread that calls GetMessage.
|
||
|
// So, we have to create the window from select_waitevent
|
||
|
}
|
||
|
|
||
|
int select_removeevent(int /*which*/)
|
||
|
{
|
||
|
//
|
||
|
// Not needed for WSA.
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int select_watchevent(struct eventreq *req, int which)
|
||
|
{
|
||
|
return select_modwatch(req, which);
|
||
|
}
|
||
|
|
||
|
int select_modwatch(struct eventreq *req, int which)
|
||
|
{
|
||
|
//
|
||
|
// If our WSAAsyncSelect window is not constructed yet, wait
|
||
|
// until it is construected. The window gets constructed when the server
|
||
|
// is done starting up, so this should only happen when select_modwatch
|
||
|
// is being called as the server is starting up.
|
||
|
while (sMsgWindow == NULL)
|
||
|
OSThread::Sleep(10);
|
||
|
|
||
|
// Convert EV_RE and EV_WR to the proper WSA event codes.
|
||
|
// WSA event codes are more specific than what POSIX provides, so
|
||
|
// just wait on any kind of read related event for EV_RE, same for EV_WR
|
||
|
SInt32 theEvent = 0;
|
||
|
|
||
|
if (which & EV_RE)
|
||
|
theEvent |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
||
|
if (which & EV_WR)
|
||
|
theEvent |= FD_WRITE | FD_CONNECT;
|
||
|
|
||
|
// This is a little bit of a hack, because we are assuming that the caller
|
||
|
// is actually putting a UInt32 in the void*, not a void*, and we are also
|
||
|
// assuming caller is not using the 0 - WM_USER range of values, but
|
||
|
// both of these things are true in the EventContext.cpp code, and this
|
||
|
// mechanism of passing around cookies is just too convienent to ignore.
|
||
|
unsigned int theMsg = (unsigned int)(req->er_data);
|
||
|
|
||
|
return ::WSAAsyncSelect(req->er_handle, sMsgWindow, theMsg, theEvent);
|
||
|
}
|
||
|
|
||
|
int select_waitevent(struct eventreq *req, void* /*onlyForMacOSX*/)
|
||
|
{
|
||
|
if (sMsgWindow == NULL)
|
||
|
{
|
||
|
//
|
||
|
// This is the first time we've called this function. Do our
|
||
|
// window initialization now.
|
||
|
|
||
|
// We basically just want the simplest window possible.
|
||
|
WNDCLASSEX theWndClass;
|
||
|
theWndClass.cbSize = sizeof(theWndClass);
|
||
|
theWndClass.style = 0;
|
||
|
theWndClass.lpfnWndProc = &select_wndproc;
|
||
|
theWndClass.cbClsExtra = 0;
|
||
|
theWndClass.cbWndExtra = 0;
|
||
|
theWndClass.hInstance = NULL;
|
||
|
theWndClass.hIcon = NULL;
|
||
|
theWndClass.hCursor = NULL;
|
||
|
theWndClass.hbrBackground = NULL;
|
||
|
theWndClass.lpszMenuName = NULL;
|
||
|
theWndClass.lpszClassName = "DarwinStreamingServerWindow";
|
||
|
theWndClass.hIconSm = NULL;
|
||
|
|
||
|
ATOM theWndAtom = ::RegisterClassEx(&theWndClass);
|
||
|
Assert(theWndAtom != NULL);
|
||
|
if (theWndAtom == NULL)
|
||
|
::exit(-1); // Poor error recovery, but this should never happen.
|
||
|
|
||
|
sMsgWindow = ::CreateWindow( "DarwinStreamingServerWindow", // Window class name
|
||
|
"DarwinStreamingServerWindow", // Window title bar
|
||
|
WS_POPUP, // Window style ( a popup doesn't need a parent )
|
||
|
0, // x pos
|
||
|
0, // y pos
|
||
|
CW_USEDEFAULT, // default width
|
||
|
CW_USEDEFAULT, // default height
|
||
|
NULL, // No parent
|
||
|
NULL, // No menu handle
|
||
|
NULL, // Ignored on WinNT
|
||
|
NULL); // data for message proc. Who cares?
|
||
|
Assert(sMsgWindow != NULL);
|
||
|
if (sMsgWindow == NULL)
|
||
|
::exit(-1);
|
||
|
}
|
||
|
|
||
|
MSG theMessage;
|
||
|
|
||
|
//
|
||
|
// Get a message for my goofy window. 0, 0 indicates that we
|
||
|
// want any message for that window.
|
||
|
//
|
||
|
// Convienently, this function blocks until there is a message, so it works
|
||
|
// much like waitevent would on Mac OS X.
|
||
|
UInt32 theErr = ::GetMessage(&theMessage, sMsgWindow, 0, 0);
|
||
|
|
||
|
if (theErr > 0)
|
||
|
{
|
||
|
UInt32 theSelectErr = WSAGETSELECTERROR(theMessage.lParam);
|
||
|
UInt32 theEvent = WSAGETSELECTEVENT(theMessage.lParam);
|
||
|
|
||
|
req->er_handle = theMessage.wParam; // the wParam is the FD
|
||
|
req->er_eventbits = EV_RE; // WSA events & socket events don't map...
|
||
|
// but the server state machines never care
|
||
|
// what the event is anyway.
|
||
|
|
||
|
// we use the message # as our way of passing around the user data.
|
||
|
req->er_data = (void*)(theMessage.message);
|
||
|
|
||
|
//
|
||
|
// We should prevent this socket from getting events until modwatch is called.
|
||
|
(void)::WSAAsyncSelect(req->er_handle, sMsgWindow, 0, 0);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Do we ever get WM_QUIT messages? Can there ever be an error?
|
||
|
Assert(0);
|
||
|
return EINTR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
LRESULT CALLBACK select_wndproc(HWND /*inWIndow*/, UINT inMsg, WPARAM /*inParam*/, LPARAM /*inOtherParam*/)
|
||
|
{
|
||
|
// If we don't return true for this message, window creation will not proceed
|
||
|
if (inMsg == WM_NCCREATE)
|
||
|
return TRUE;
|
||
|
|
||
|
// All other messages we can ignore and return 0
|
||
|
return 0;
|
||
|
}
|