/* * * @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; }