;Homer's IOCP Networking Engine ;This file contains a bunch of necessary data declarations (structs and so forth), ;as well as 'almost' all of the necessary 'includes' required. ;The following files must be included by YOU in your application: ;- ws2_32 and Mswsock (inc and lib) ;- Stream, Collection, and DwordCollection object classes OPERATION_ENDED equ 666 OPERATION_DOACCEPT equ 08008h OPERATION_DOWRITE equ 0BEEFh OPERATION_WRITTEN equ 0d00dh OPERATION_READ equ 0F00Dh OPERATION_CONNECT equ 04321h ERROR_BADPROTOCOL equ -1 ERROR_BADVERSION equ -2 ERROR_USERQUIT equ -666 CLIENT_DISCONNECTED equ 0FFFFFFFFh WSA_FLAG_OVERLAPPED equ 1 WSA_INVALID_EVENT equ 00h WSA_FLAG_OVERLAPPED equ 01h MSG_PARTIAL equ 8000h SO_UPDATE_ACCEPT_CONTEXT equ 700Bh WSAEVENT typedef HANDLE WSAOVERLAPPED struct Internal DWORD ? InternalHigh DWORD ? an_Offset DWORD ? OffsetHigh DWORD ? hEvent WSAEVENT ? WSAOVERLAPPED ends PWSAOVERLAPPED typedef ptr WSAOVERLAPPED WSABUF struct len DWORD ? buf PBYTE ? WSABUF ends PWSABUF typedef ptr WSABUF XOVL struct ovl WSAOVERLAPPED <> wsabuf WSABUF <> bytesused dd ? ;#bytes currently in buffer operation dd ? bytes dd ? ;#bytes due to this operation piojob dd ? ;ptr to wrapper object pbuforig dd ? ;original copy of wsabuf.buf pointer bufsizeorig dd ? ;original copy of wsabuf.len value XOVL ends IOC_WS2 equ 008000000h SIO_GET_EXTENSION_FUNCTION_POINTER equ IOC_INOUT or IOC_WS2 or 6 SO_UPDATE_CONNECT_CONTEXT equ 07010h .data ConnectExGuid GUID <25a207b9h,0ddf3h,4660h,{8eh,0e9h,76h,0e5h,8ch,74h,06h,3eh}> .code ;Networking framework MakeObjects UPNPNAT ;Support for Universal Plug n Play based NAT Traversal (Port Forwarding) ;MakeObjects NetApp ;Abstract class for the Application to talk to NetEngine MakeObjects Pool ;BaseClass for recycling of arbitrary derived objects MakeObjects IOJob ;this object represents one package of network data, owned by a Client MakeObjects IOJobPool ;Derived class for recycling of IOJob objects MakeObjects NetworkProtocol ;BaseClass for handling of Network Events MakeObjects Client ;this object represents one TCP/IP network session, or if you like, "a live connection with remote user" MakeObjects ClientPool ;Derived class for recycling of Client objects MakeObjects ClientGroup ;Support for arbitrary and hierarchical grouping of clients (eg chat channel) ;MakeObjects BaseProtocol ;Foundation of our protocol enforcement ;MakeObjects LobbyProtocol ;Actual useful protocol implementation ;MakeObjects GameProtocol ;TODO ;============================================================= NetEngineID equ 32840 Object NetEngine,NetEngineID,Primer RedefineMethod Init, dword,dword,dword RedefineMethod Done VirtualMethod Listen, Pointer,dword ;pProtocol,dListenPort VirtualMethod ConnectTo,Pointer,dword,dword,LPSTR,LPSTR ;pProtocol,dwHost,dwPort,pUsernameString,pPasswordString VirtualMethod UDP_Broadcast,Pointer,dword,dword,Pointer,dword;pProtocol,dwBroadcastAddress,dwPort,pData,dLen Private VirtualMethod GoodbyeClient,Pointer,Pointer ;pClient, pJob VirtualMethod OnIOCompleted,Pointer,dword ;-> XOVL, dwBytes VirtualMethod QueueAcceptorClient,Pointer VirtualMethod Worker ;This method counts available number of logical cpus VirtualMethod GetLogicalCPUCount PrivateEnd DefineVariable wsadata,WSADATA,{} DefineVariable io_completion_port,Pointer,NULL DefineVariable end_event,dword,NULL DefineVariable ShuttingDown,BOOL,FALSE DefineVariable dMinimum_Pending_Accepts,dword,0 DefineVariable NumWorkerThreads,dword,NULL ;#Worker Threads waiting for jobs to complete Embed RootClientGroup,ClientGroup ;Support for a Tree of Named communication channels Embed InClients, ClientPool ;Pool of INBOUND Clients Embed OutClients, ClientPool ;Pool of OUTBOUND Clients Embed Listeners, ClientPool ;Pool of LISTENING Clients Embed IOJobs, IOJobPool ;Pool of IO Jobs ; Embed Nat,NATUPNP ;Support for NAT Traversal via UPNP ObjectEnd ;============================================================= align 4 if IMPLEMENT ; 覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧 ;This method allocates a new Client and enqueues an Accept io job. Method NetEngine.QueueAcceptorClient,uses esi,pListener LOCAL pClient SetObject esi ;Allocate a Client, telling it to use the Listener's protocol mov pClient,$OCall ([esi].InClients::ClientPool.Allocate) mov edx,pListener push edx OCall pClient::Client.Init, [esi].io_completion_port,addr [esi].IOJobs,[edx].Client.pProtocol,pListener, FALSE ;Set Listener field mov eax,pClient pop [eax].Client.pListener ;Queue the accept job mov edx,pListener OCall pClient::Client.QueueAccept,[edx].Client.hSocket MethodEnd ; 覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧 ;Destructor method - trash 'everything' :) Method NetEngine.Done, uses esi SetObject esi ;Tell NetEngine Worker to die, and wait for the Death mov [esi].ShuttingDown,TRUE .while [esi].NumWorkerThreads!=0 invoke Sleep,500 .endw ;Destroy Events invoke CloseHandle, [esi].io_completion_port invoke CloseHandle, [esi].end_event ;Clean up resource pools OCall [esi].IOJobs::IOJobPool.Done OCall [esi].Listeners::ClientPool.Done OCall [esi].InClients::ClientPool.Done OCall [esi].OutClients::ClientPool.Done OCall [esi].RootClientGroup::ClientGroup.Done ;Close down WinSock invoke WSACleanup MethodEnd ;Constructor method - initialize internal collections, threads, IOCP etc. ;Returns eax=pThis or NULL=Failed Method NetEngine.Init,uses esi,MinClients,MaxClients,MaxIOJobs LOCAL pClient,pJob,tid,NumWorkers SetObject esi invoke WSAStartup, 0202h, addr [esi].wsadata .if eax!= NULL DbgWarning "FAILED TO START WINSOCK 2.2 - QUITTING" xor eax,eax ExitMethod .endif m2m [esi].dMinimum_Pending_Accepts, MinClients ;Initialize some collections OCall [esi].InClients::ClientPool.Init,esi, MaxClients OCall [esi].OutClients::ClientPool.Init,esi, MaxClients OCall [esi].Listeners::ClientPool.Init,esi, MaxClients OCall [esi].IOJobs::IOJobPool.Init,esi, MaxIOJobs, 4096 ;The Root ClientGroup should be initialized with pOwner==NULL ;because this hierarchical object uses pOwner to point to Parent OCall [esi].RootClientGroup::ClientGroup.Init,NULL,$OfsCStr("Root"),$OfsCStr("Mother of all evil") ;Create the IOCP invoke CreateIoCompletionPort, INVALID_HANDLE_VALUE, 0, 0, 0 .if eax==NULL DbgWarning "FAILED TO CREATE IO COMPLETION PORT - QUITTING" jmp @F .endif mov [esi].io_completion_port, eax ;Create a special event to signal Worker Threads to terminate push esi invoke CreateEvent, 0, TRUE, FALSE, 0 pop esi mov [esi].end_event, eax .if eax== NULL DbgWarning "FAILED TO CREATE KILLNetEngine EVENT OBJECT - QUITTING" jmp @F .endif ;Create one Worker Thread per available logical cpu mov NumWorkers, $OCall (esi.GetLogicalCPUCount) DbgDec eax,"Number of available logical cpus" xor ebx,ebx .while ebx