Author Topic: IO Completion ports tracking multiple completion keys  (Read 3583 times)

Frank

  • Regular Member
  • *
  • Posts: 8
IO Completion ports tracking multiple completion keys
« on: November 13, 2017, 02:53:52 PM »
Hi,

I have an issue tracking completion keys upon returning from GetQueuedCompletionStatus.

My application is receiving first connection with a unique context which is just a memory allocated upon accept. This one is associated to the main socket. This socket is used for commands for send pm, initial ping. And such other small size commands.
 
The first connection will be that the user is joined to the conversation and so that it will be added to the listview. The lparam of LVM_INSERTITEM will contain this completion key (The main one). The worker threads will notify the GUI main thread about a new user joined via SendNotifyMessage with a custom message. When the main thread receives this message it will initiate a first ping request to the client so it will instruct it to create a new socket for ping and connect it.

On Initial ping command the client will create a new socket and connect it to my application then send a ping data. Upon receiving this ping data at this point my application got 2 completion keys for the same user. Here i run into an issue that i can no longer track this current ping data belongs to which user. As the ping completion key returns different completion key from GetQueuedCompletionStatus than the main one. I can not use LVM_FINDITEM since this ping completion key is not added in listview lparam but the main one is added instead. Now how would i keep a list of completion keys for each user?

Each socket created will have it's own completion key.

My completion key is below. I define OvIn and OvOut as extended overlapped structures inside this CONTEXT_KEY structure

Code: [Select]
CONTEXT_KEY struct

   
    LastTimeDataSent dd
    PingSentTimeMs dd ?
    PongReceivedTimeMs dd ?
    LastTimePingedMs dd ?
   
   
    OvIn PER_IO_DATA <>
    OvOut     PER_IO_DATA <>
   
   
   
   
    chInBuf        LPDWORD 
 

    TotalBytesReceived    DWORD ?
    TotalBytesSent    DWORD ?
   
 
   
CONTEXT_KEY ends



PER_IO_DATA STRUCT
ov           OVERLAPPED <>
    socket      SOCKET ?
    BytesTransferred   DWORD ?
  ClientAddr   sockaddr_in <>
  ClientAddrResolved   db 32 dup(?)
    wsaBuf      WSABUF <>
SizeOfClientAddr   dd ?
    dwFlags      DWORD ?
    OP_CODE   dd ?

Buffer    db 1000h dup(?)
CSECTION    CRITICAL_SECTION <>
PER_IO_DATA ends











These memory allocations won't be de allocated until the user is disconnected.

I have thought about adding a random unique key per data that is used for main and ping in each send from client so upon receivng these data my application will loop through the listview and grab each user connection key of the main socket then compare it with the ping socket connection key and if they match then this is the user that pinged, but i think this is a poor idea.
I would appreciated any help in this matter.

AW

  • Member
  • *****
  • Posts: 2312
  • Let's Make ASM Great Again!
Re: IO Completion ports tracking multiple completion keys
« Reply #1 on: November 13, 2017, 05:26:18 PM »
Probably, most people here will not bother to solve your IO Completion Ports school assignment.
 :badgrin:

Frank

  • Regular Member
  • *
  • Posts: 8
Re: IO Completion ports tracking multiple completion keys
« Reply #2 on: November 13, 2017, 05:44:13 PM »
Probably, most people here will not bother to solve your IO Completion Ports school assignment.
 :badgrin:

First this isn't a school assignment.
Why would you bother posting nonsense? this isn't a spam or joke section.

AW

  • Member
  • *****
  • Posts: 2312
  • Let's Make ASM Great Again!
Re: IO Completion ports tracking multiple completion keys
« Reply #3 on: November 13, 2017, 06:09:42 PM »
No?  :shock:

jj2007

  • Member
  • *****
  • Posts: 9684
  • Assembler is fun ;-)
    • MasmBasic
Re: IO Completion ports tracking multiple completion keys
« Reply #4 on: November 13, 2017, 06:47:31 PM »
> Here i run into an issue that i can no longer track this current ping data belongs to which user.

Hi Frank,

Welcome to the Forum. Can't you allocate an array of QWORDs and access the key via an index?
Code: [Select]
  mov eax, maxusers*8 ; 8=QWORD
  mov ebx, alloc(eax)
  mov eax, index ; e.g. 3
  mov [ebx+8*eax], edx ; store key A
  mov [ebx+8*eax+4], edx ; store key B
  ...
  mov edx, [ebx+8*eax] ; retrieve keyA
  mov edx, [ebx+8*eax+4] ; retrieve keyB

Frank

  • Regular Member
  • *
  • Posts: 8
Re: IO Completion ports tracking multiple completion keys
« Reply #5 on: November 14, 2017, 05:33:15 AM »
jj2007 thank you for your welcome message.

The issue is not about where to store the context keys. I can allocate an array and store them there.
But the main issue is that when a ping is issued from server to client it is first issued with the main context which uses different address than the one that will receive the ping. So 1 context send and other context receive. At the point where the ping arrives there is no way for me to tell that this current data belongs to this specific main context. Since each return from GetQueuedCompletionStatus pulls different context key and so the ping can arrive in out of sequence order. I can not rely on list view count. Since on multiple users the ping of first user can arrive before the last one and so on. So the only solution i think is to provide a unique connection ID which will be used in all further communications (All contexts will carry this ID). This way it will be easy to tell which user this is. I think i will stick with just 1 socket and 1 context per user for all communications and just use multiple Per io data instead. Allocate each one at start of new operation and de allocate it once all the packets have been processed.

jj2007

  • Member
  • *****
  • Posts: 9684
  • Assembler is fun ;-)
    • MasmBasic
Re: IO Completion ports tracking multiple completion keys
« Reply #6 on: November 14, 2017, 08:27:30 AM »
So 1 context send and other context receive.

OK, got it. This is one of my underdeveloped areas :redface:
So, no way to send a ping and wait for a response from this client?

AW

  • Member
  • *****
  • Posts: 2312
  • Let's Make ASM Great Again!
Re: IO Completion ports tracking multiple completion keys
« Reply #7 on: November 14, 2017, 09:44:07 PM »
OK, got it. This is one of my underdeveloped areas :redface:
So, no way to send a ping and wait for a response from this client?
Don't be sad JJ  ;). Actually PING is a wrong term here, the term is just CONNECTION and we are very likely talking about TCP connections. I never heard about IOCP for ICMP, which although not impossible would require RAW SOCKETS, which are highly restricted since Windows Vista.
Anyway, I don't see a single line of code in this question, all I see is a badly formulated problem which looks unreal like a school assignment.

felipe

  • Member
  • *****
  • Posts: 1249
  • Eagles are just great!
Re: IO Completion ports tracking multiple completion keys
« Reply #8 on: November 15, 2017, 12:02:00 PM »
@aw27:
Probably you are right. In the "code" above there are only structures defined.  :eusa_snooty:

@Frank:
Maybe you can upload some code to prove that aw27 is wrong?  :bgrin:
Felipe.

Frank

  • Regular Member
  • *
  • Posts: 8
Re: IO Completion ports tracking multiple completion keys
« Reply #9 on: November 17, 2017, 01:57:36 AM »
OK, got it. This is one of my underdeveloped areas :redface:
So, no way to send a ping and wait for a response from this client?
Don't be sad JJ  ;). Actually PING is a wrong term here, the term is just CONNECTION and we are very likely talking about TCP connections. I never heard about IOCP for ICMP, which although not impossible would require RAW SOCKETS, which are highly restricted since Windows Vista.
Anyway, I don't see a single line of code in this question, all I see is a badly formulated problem which looks unreal like a school assignment.

I never mentioned ICMP protocol. This is just a normal small data share over TCP each x seconds to avoid lose of close notification. Since i noticed the client will lose close notification in case if the server is closed if long time elapsed without data share.


@aw27:
Probably you are right. In the "code" above there are only structures defined.  :eusa_snooty:

@Frank:
Maybe you can upload some code to prove that aw27 is wrong?  :bgrin:

Server code:

Connection accepting:
Code: [Select]
AcceptConnection proc pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED





invoke AddConnectionSlot,pContextKey,pOverlapped
.if EAX != NULL
MOV EDI,EAX ;pContextKey
MOV [ESI].PER_IO_DATA.OP_CODE,OP_ACCEPTING





invoke AcceptExFunc,[Listen],[ESI].PER_IO_DATA.socket,addr [ESI].PER_IO_DATA.Buffer,NULL,sizeof PER_IO_DATA.ClientAddr*2,\
sizeof PER_IO_DATA.ClientAddr*2,addr [ESI].PER_IO_DATA.BytesTransferred,addr [ESI].PER_IO_DATA.ov
invoke CreateIoCompletionPort, [ESI].PER_IO_DATA.socket, [CompletionPort], EDI, NULL


.endif


ret
AcceptConnection endp


AddConnectionSlot is just used for allocation user context using HeapAlloc.


Code: [Select]
AddConnectionSlot proc pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED

     
invoke HeapAlloc,[HeapH],HEAP_ZERO_MEMORY ,sizeof CONTEXT_KEY
MOV pContextKey, EAX

MOV EDX,pContextKey
LEA EBX,[EAX].CONTEXT_KEY.OvIn
MOV pOverlapped,EBX








MOV EAX,pOverlapped
MOV [EAX].PER_IO_DATA.pPContextKey,EDX




invoke HeapAlloc,[HeapH],HEAP_ZERO_MEMORY ,sizeof InitialReadBuffSIze


MOV EDX,pContextKey
MOV [EDX].CONTEXT_KEY.SizeOfOverAllRecvBuffer,InitialReadBuffSIze
MOV [EDX].CONTEXT_KEY.chInBuf,EAX
MOV ESI,EDX
MOV EAX,sizeof PER_IO_DATA.ClientAddr
MOV [ESI].PER_IO_DATA.SizeOfClientAddr,EAX




[ESI].CONTEXT_KEY.SizeOfClientAddr

       

invoke WSASocket,AF_INET,SOCK_STREAM,NULL,NULL,NULL,WSA_FLAG_OVERLAPPED
MOV EBX,EAX
MOV EAX,pContextKey
LEA EDX,[EAX].CONTEXT_KEY.OvIn
MOV [EDX].PER_IO_DATA.socket,EBX

LEA EDX,[EAX].CONTEXT_KEY.OvOut
MOV [EDX].PER_IO_DATA.socket,EBX
MOV ESI,pOverlapped
ret

AddConnectionSlot endp


Listen function:

Code: [Select]
Listen_Function proc pServer:PFASTSERVER
local pContextKey:PCONTEXT_KEY
    local pOverlapped:POVERLAPPED
LOCAL numBytes:DWORD

   
invoke WSAStartup,0202h,addr wsd
invoke WSASocket,AF_INET,SOCK_STREAM,NULL,NULL,NULL,WSA_FLAG_OVERLAPPED
MOV ESI,EAX
invoke WSAIoctl,ESI,SIO_GET_EXTENSION_FUNCTION_POINTER,addr WSAID_ACCEPTEX,sizeof WSAID_ACCEPTEX,addr AcceptExPtr\
,sizeof AcceptExPtr,addr numBytes,NULL,NULL
invoke closesocket,ESI

invoke CreateIoCompletionPort,INVALID_HANDLE_VALUE,NULL,NULL,NULL
MOV [CompletionPort],EAX
mov edx, pServer
    mov [edx].FASTSERVER.hIOCompletionPort, eax

MOV [CompletionPortAccept],EAX


   
MOV ESI,NumberOfConcurrentThreads
.while ESI != NULL
invoke CreateThread,NULL,NULL,addr IOWorkerThreads,pServer,NULL,NULL

invoke CloseHandle,EAX
DEC ESI
INC NumberOfThreadsCreated
.endw

invoke WSASocket,AF_INET,SOCK_STREAM,NULL,NULL,NULL,WSA_FLAG_OVERLAPPED
MOV [Listen],EAX
invoke CreateIoCompletionPort, [Listen], [CompletionPort], NULL, NULL
invoke htons,Port
MOV InternetAddr.sin_port, AX
MOV InternetAddr.sin_family, AF_INET
MOV InternetAddr.sin_addr, INADDR_ANY

invoke bind, Listen, addr InternetAddr, SizeOf InternetAddr
invoke listen,Listen,SOMAXCONN













invoke CreateEvent,NULL,FALSE,FALSE,NULL
MOV [hEventObject],EAX
invoke WSAEventSelect,[Listen],[hEventObject],FD_ACCEPT
MOV EDI,EAX
ACCEPT:
invoke WSAWaitForMultipleEvents,1,addr hEventObject,FALSE,WSA_INFINITE,FALSE

           invoke AcceptConnection,pContextKey,pOverlapped
JMP  ACCEPT

ret

Listen_Function endp


The IO Worker thread pool function

Code: [Select]
IOWorkerThreads proc  pServer:PFASTSERVER
local hIOCompletionPort:HANDLE
    local BytesTransferred:DWORD
    local pContextKey: PTR DWORD
    local pOverlapped:PTR DWORD
   

   
    mov edx, pServer
   
    mov ecx, [edx].FASTSERVER.hIOCompletionPort
    mov hIOCompletionPort, ecx


START:


MOV pContextKey,NULL
MOV [BytesTransferred],NULL
MOV pOverlapped,NULL
invoke GetQueuedCompletionStatus, hIOCompletionPort, addr BytesTransferred,addr pContextKey, addr pOverlapped, INFINITE

    .if EAX == FALSE   
    .if [pOverlapped] == NULL
   
    invoke GetLastError
    .if EAX == WAIT_TIMEOUT
    JMP START
    .else
   
    RET
   
   
   
   
    ret
    .endif
   
    .else
        .if pOverlapped != NULL
    invoke Cleanup,pContextKey,pOverlapped,DC_BY_IO
    JMP START
    .endif
   
    .endif
   
   
    .elseif EAX == TRUE
   
    .if [BytesTransferred] == NULL
    MOV EDX,pOverlapped
    .if [EDX].PER_IO_DATA.OP_CODE == OP_READ
   
    invoke Cleanup,pContextKey,pOverlapped,DC_BY_IO
    JMP START
    .endif
   
    .endif
   
   
   

   
    .endif
     
     
   
     
     
   
   

    MOV EDX,pOverlapped
Switch [EDX].PER_IO_DATA.OP_CODE

    Case OP_ACCEPTING
MOV ESI,pOverlapped
MOV EDI,pContextKey
MOV EAX,sizeof PER_IO_DATA.ClientAddr
MOV [ESI].PER_IO_DATA.SizeOfClientAddr,EAX
invoke setsockopt,[ESI].PER_IO_DATA.socket,SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, addr  [Listen],4
invoke getpeername,[ESI].PER_IO_DATA.socket,addr [ESI].PER_IO_DATA.ClientAddr,addr [ESI].PER_IO_DATA.SizeOfClientAddr

MOV ECX,DWORD PTR [ESI].PER_IO_DATA.ClientAddr.sin_addr
invoke inet_ntoa, ECX

LEA EDI,[ESI].PER_IO_DATA.ClientAddrResolved
MOV ESI,EAX ;Buffer of dotted ip address
invoke lstrlen,ESI
MOV ECX,EAX
REP MOVSB







invoke InitialIORead,pContextKey,pOverlapped

   

   
 
 
    Case OP_READ
    invoke ProcessReadIO,pContextKey,pOverlapped,[BytesTransferred] 
     
 
    CASE OP_WRITE
    MOV EDX,pContextKey
    MOV EBX,pOverlapped
    MOV ECX,BytesTransferred
    ADD [EDX].CONTEXT_KEY.TotalBytesSent,ECX
    MOV ECX,[EDX].CONTEXT_KEY.TotalBytesSent
   
   
    .if ECX < [EBX].PER_IO_DATA.Buffer.PACKET_INFO.PACKET_SIZE
   
    invoke ProcessWriteIO,pContextKey,pOverlapped,[BytesTransferred]
   
    .elseif ECX ==  [EBX].PER_IO_DATA.Buffer.PACKET_INFO.PACKET_SIZE
    MOV [EDX].CONTEXT_KEY.TotalBytesSent,0 ;Reset sent size
    invoke IOWriteDone,pContextKey,pOverlapped,[BytesTransferred]
   
    .endif
     
Case OP_CLOSE
invoke Cleanup,pContextKey,pOverlapped,DC_BY_IO
Default
     
Endsw

    JMP START
   
   
   
   

   
   
   
   

ret

IOWorkerThreads endp

Cleanup procedure
Code: [Select]
Cleanup Proc USES ESI EDI  pContextKey:DWORD,pOverlapped:DWORD,COMMAND:DWORD

MOV EDI, pContextKey
MOV ESI,pOverlapped

    .if pContextKey != NULL
   
   
   
   
   


.if [ESI].PER_IO_DATA.socket  != SOCKET_ERROR ;Not closed by right click Disconnect command
invoke  SendNotifyMessage, MainTabContentDialogHandle, LV_CMD_REMOVE_USER,pContextKey,pOverlapped
invoke closesocket,[ESI].PER_IO_DATA.socket
MOV [ESI].PER_IO_DATA.socket,SOCKET_ERROR


   
.endif




MOV ESI,[EDI].CONTEXT_KEY.chInBuf

    invoke HeapFree,[HeapH],NULL,ESI
    invoke HeapFree,[HeapH],NULL,EDI
   
   
   
   
    .endif

ret

Cleanup endp

Proccess IO Read (WSARecv)
Code: [Select]
ProcessReadIO proc pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED,BytesTransferred:DWORD

 
 
 
 
 
 
 
  MOV EDX,pContextKey
  MOV EBX, pOverlapped
  MOV ECX,[BytesTransferred]
       LEA ESI,[EBX].PER_IO_DATA.Buffer
       
       MOV EDI,[EDX].CONTEXT_KEY.chInBuf
       
       ADD EDI,[EDX].CONTEXT_KEY.TotalBytesReceived
       REP MOVSB
       MOV EBX,[BytesTransferred]
       ADD [EDX].CONTEXT_KEY.TotalBytesReceived,EBX
       

   
   MOV EDX,pContextKey
       MOV EBX,pOverlapped
     
   
      MOV EDX,pContextKey
      MOV EDI,[EDX].CONTEXT_KEY.chInBuf ;Dynamic buffer...
     
     
    .if DWORD PTR [EDI].PACKET_INFO.DATA_START == DATA_START ;ID
    MOV EDX,pContextKey
    MOV ECX,[EDX].CONTEXT_KEY.TotalBytesReceived
    MOV ESI, [EDI].PACKET_INFO.PACKET_SIZE
   
   
   
   
    .if ESI == ECX
    ;Finished receving all data... parse it and act depend on what command is...
    MOV [EDX].CONTEXT_KEY.TotalBytesReceived,0
    SWITCH [EDI].PACKET_INFO.MAIN_COMMAND
   
   
    CASE CMD_ADDNEW
   

invoke SendMessage,MainTabContentDialogHandle,LV_CMD_ADD_USER,pContextKey,pOverlapped
 

   
    CASE CMD_PONG
    invoke GetTickCount
    MOV EDX,pContextKey
    MOV [EDX].CONTEXT_KEY.PongReceivedTimeMs,EAX

    invoke SendNotifyMessage,MainTabContentDialogHandle,LV_MESSAGE_CALCULATE_PING,pContextKey,pOverlapped
   
    Default
   
    ENDSW
   
   

   
   
   
    .else
   
    .endif
    MOV EDX,pContextKey
LEA EDX,[EDX].CONTEXT_KEY.OvIn
       
       
       
          mov [edx].PER_IO_DATA.wsaBuf.len, sizeof PER_IO_DATA.Buffer
        lea ecx, [edx].PER_IO_DATA.Buffer
    mov [edx].PER_IO_DATA.wsaBuf.buf, ecx
    MOV [edx].PER_IO_DATA.BytesTransferred,NULL
    MOV [edx].PER_IO_DATA.OP_CODE,OP_READ
        invoke WSARecv, [edx].PER_IO_DATA.socket, addr [EDX].PER_IO_DATA.wsaBuf, 1,
            addr [edx].PER_IO_DATA.BytesTransferred, addr [EDX].PER_IO_DATA.dwFlags,
            addr [EDX].PER_IO_DATA.ov, NULL 
       

    .else
    invoke Cleanup,pContextKey,pOverlapped,DC_BY_IO
    .endif
     
     
 



ret

ProcessReadIO endp

Process IO Write (WSASend)
Code: [Select]
ProcessWriteIO proc pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED,BytesTransferred:DWORD
MOV EDX,pOverlapped


mov [edx].PER_IO_DATA.OP_CODE,OP_WRITE
MOV ECX,[EDX].PER_IO_DATA.Buffer.PACKET_INFO.PACKET_SIZE
    mov [edx].PER_IO_DATA.wsaBuf.len, ECX
    lea ecx, [EDX].PER_IO_DATA.Buffer
    mov [edx].PER_IO_DATA.wsaBuf.buf, ECX
 
 

invoke WSASend,  [edx].PER_IO_DATA.socket, addr [edx].PER_IO_DATA.wsaBuf, 1,
               addr [edx].PER_IO_DATA.BytesTransferred, NULL,
               addr [edx].PER_IO_DATA.ov, NULL

ret

ProcessWriteIO endp

InitialIORead (First WSARecv to let data arrive)

Code: [Select]
InitialIORead proc pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED

mov edx, pOverlapped

mov [edx].PER_IO_DATA.OP_CODE,OP_READ
    mov [edx].PER_IO_DATA.wsaBuf.len, sizeof PER_IO_DATA.Buffer
    lea ecx, [edx].PER_IO_DATA.Buffer
    mov [edx].PER_IO_DATA.wsaBuf.buf, ecx
 

    invoke WSARecv,  [edx].PER_IO_DATA.socket, addr [edx].PER_IO_DATA.wsaBuf, 1,
               addr [edx].PER_IO_DATA.BytesTransferred, addr [edx].PER_IO_DATA.dwFlags,
               addr [edx].PER_IO_DATA.ov, NULL
               


ret

InitialIORead endp


SendCommand Procedure:
Code: [Select]
SendCommand Proc USES ESI EDI EAX hWnd:HWND, pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED,COMMAND:DWORD,SUB_COMMAND:DWORD
LOCAL Buffer:DWORD
LOCAL CaptionLen:DWORD
LOCAL TextLen:DWORD


MOV ESI,pContextKey
MOV EDI,pOverlapped





invoke AddCommandToBuffer,addr [ESI].CONTEXT_KEY.OvOut.Buffer,sizeof PER_IO_DATA.Buffer,COMMAND,SUB_COMMAND
MOV Buffer,EAX



SWITCH COMMAND



CASE CMD_CLOSE_CONNECTION
MOV [ESI].CONTEXT_KEY.OvOut.Buffer.PACKET_INFO.PACKET_SIZE,Sizeof PACKET_INFO
MOV [ESI].CONTEXT_KEY.OvOut.OP_CODE,OP_WRITE
MOV [ESI].CONTEXT_KEY.OvIn.OP_CODE,OP_CLOSE



CASE CMD_INITIAL_PING
MOV [ESI].CONTEXT_KEY.OvOut.Buffer.PACKET_INFO.PACKET_SIZE,Sizeof PACKET_INFO
MOV [ESI].CONTEXT_KEY.OvOut.OP_CODE,OP_WRITE

CASE CMD_PING
MOV [ESI].CONTEXT_KEY.OvOut.Buffer.PACKET_INFO.PACKET_SIZE,Sizeof PACKET_INFO
MOV [ESI].CONTEXT_KEY.OvOut.OP_CODE,OP_WRITE

DEFAULT

ENDSW












invoke PostQueuedCompletionStatus,[CompletionPort],NULL,ESI,addr [ESI].CONTEXT_KEY.OvOut



ret

SendCommand endp




Frank

  • Regular Member
  • *
  • Posts: 8
Re: IO Completion ports tracking multiple completion keys
« Reply #10 on: November 17, 2017, 02:01:34 AM »
Client:
Code: [Select]
Main proc pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED,pServer:PFASTSERVER

LOCAL NetworkEvents:WSANETWORKEVENTS
LOCAL pContextKeyPing:PCONTEXT_KEY


invoke HeapCreate, NULL,4,NULL
MOV [HeapH],EAX
invoke WSAStartup,0202h,addr wsd


invoke InitializeContext
MOV pContextKey, EAX

LEA EBX,[EAX].CONTEXT_KEY.OvOut
MOV pOverlapped,EBX









invoke CreateSocket

.if EAX != SOCKET_ERROR


MOV ESI,pServer
MOV EDI,pContextKey
MOV MainSocket,EAX
MOV [EDI].CONTEXT_KEY.OvIn.socket,EAX
MOV [EDI].CONTEXT_KEY.OvOut.socket,EAX
invoke CreateIoCompletionPort,INVALID_HANDLE_VALUE,NULL,NULL,NULL
MOV [ESI].FASTSERVER.hIOCompletionPort,EAX
MOV [CompletionPort],EAX
invoke CreateEvent,NULL,TRUE,FALSE,NULL

MOV MainSocketEvents,EAX
MOV [EDI].CONTEXT_KEY.OvOut.hSocketStatusEvent,EAX

invoke CreateEvent,NULL,TRUE,FALSE,NULL
MOV [EDI].CONTEXT_KEY.OvIn.hSocketStatusEvent,EAX

invoke CreateEvent,NULL,TRUE,FALSE,NULL
MOV [EDI].CONTEXT_KEY.OvIn.hCommandsEvent,EAX
MOV [EDI].CONTEXT_KEY.OvOut.hCommandsEvent,EAX


invoke InitializeIOWorkerThreads,pServer
invoke InitializeSocket,pContextKey,pOverlapped,pServer

MOV EDI,pContextKey
MOV [EDI].CONTEXT_KEY.OvOut.OP_CODE,OP_CONNECTING



.repeat
invoke ConnectSocket,pContextKey,pOverlapped
invoke WaitForSocketConnection,[EDI].CONTEXT_KEY.OvOut.hSocketStatusEvent,1000
.until EAX == WAIT_OBJECT_0


invoke ResetEvent,[EDI].CONTEXT_KEY.OvOut.hSocketStatusEvent
invoke RetrievePCInfo,addr [EDI].CONTEXT_KEY.OvOut.Buffer,addr [EDI].CONTEXT_KEY.OvOut.BufferSize ;Get Serial of harddrive to issue a ban on the specific PC
invoke InitialIORead,pContextKey,addr [EDI].CONTEXT_KEY.OvIn
invoke ProcessWriteIO,pContextKey,addr [EDI].CONTEXT_KEY.OvOut,NULL




.while TRUE
invoke WaitForSocketDisconnectionAndCommands,addr [EDI].CONTEXT_KEY.OvIn.hSocketStatusEvent,20000 ;Wait for the main socket for commands or DC
.if EAX != WAIT_TIMEOUT
MOV EDI,pContextKey
LEA EDX,[EDI].CONTEXT_KEY.OvIn.hSocketStatusEvent
MOV EDX,[EDX+EAX*4]

SWITCH EDX

CASE [EDI].CONTEXT_KEY.OvIn.hSocketStatusEvent

SWITCH [EDI].CONTEXT_KEY.OvIn.OP_CODE

CASE OP_DISCONNECTED_BY_NETWORK

MOV EDI,pContextKey
invoke closesocket,[EDI].CONTEXT_KEY.OvIn.socket
MOV [EDI].CONTEXT_KEY.TotalBytesReceived,0

invoke CreateSocket

        invoke InitializeSocket,pContextKey,pOverlapped,pServer
       


MOV [EDI].CONTEXT_KEY.OvIn.OP_CODE,NULL
MOV [EDI].CONTEXT_KEY.OvOut.OP_CODE, OP_RECONNECT
.repeat
invoke ConnectSocket,pContextKey,pOverlapped
invoke WaitForSocketConnection,[EDI].CONTEXT_KEY.OvOut.hSocketStatusEvent,1000
.until EAX == WAIT_OBJECT_0
MOV EDI,pContextKey





invoke ResetEvent,[EDI].CONTEXT_KEY.OvOut.hSocketStatusEvent
invoke ResetEvent,[EDI].CONTEXT_KEY.OvIn.hSocketStatusEvent
invoke ResetEvent,[EDI].CONTEXT_KEY.OvIn.hCommandsEvent

invoke RetrievePCInfo,addr [EDI].CONTEXT_KEY.OvOut.Buffer,addr [EDI].CONTEXT_KEY.OvOut.BufferSize
invoke InitialIORead,pContextKey,addr [EDI].CONTEXT_KEY.OvIn
invoke ProcessWriteIO,pContextKey,addr [EDI].CONTEXT_KEY.OvOut,NULL






CASE OP_DISCONNECTED_BY_COMMAND
MOV EDI,pContextKey
invoke closesocket,[EDI].CONTEXT_KEY.OvIn.socket

invoke CloseHandle,[EDI].CONTEXT_KEY.OvIn.hSocketStatusEvent
invoke CloseHandle,[EDI].CONTEXT_KEY.OvOut.hSocketStatusEvent
invoke CloseHandle,[EDI].CONTEXT_KEY.OvIn.hCommandsEvent
MOV [EDI].CONTEXT_KEY.OvIn.OP_CODE,OP_SHUTDOWN
.repeat
invoke PostQueuedCompletionStatus,[CompletionPort],NULL,EDI,addr [EDI].CONTEXT_KEY.OvIn
DEC NumberOfThreadsCreated
.until NumberOfThreadsCreated == 0
invoke CloseHandle,pServer.FASTSERVER.hIOCompletionPort
.break

DEFAULT

ENDSW








DEFAULT

ENDSW








.elseif EAX == WAIT_TIMEOUT
MOV EDI,pContextKey
invoke GetTickCount
LEA EDX,[EDI].CONTEXT_KEY.OvIn.Buffer
MOV ECX,[EDX].PACKET_INFO.SUB_COMMAND
SUB EAX,ECX
.if EAX > 60000

MOV [EDI].CONTEXT_KEY.OvIn.OP_CODE, OP_DISCONNECTED_BY_NETWORK
        invoke SetEvent,[EDI].CONTEXT_KEY.OvIn.hSocketStatusEvent
.endif



.else
.break

.endif
.endw



ret

Main endp

Code: [Select]
WaitForSocketDisconnectionAndCommands proc Events:LPHANDLE,WaitTime:DWORD
invoke WaitForMultipleObjects,2,Events,FALSE,WaitTime

ret

WaitForSocketDisconnectionAndCommands endp


InitializeContext
Code: [Select]
InitializeContext proc

invoke HeapAlloc,[HeapH],HEAP_ZERO_MEMORY ,sizeof CONTEXT_KEY
MOV [EAX].CONTEXT_KEY.OvIn.BufferSize,sizeof PER_IO_DATA.Buffer
MOV [EAX].CONTEXT_KEY.OvOut.BufferSize,sizeof PER_IO_DATA.Buffer
ret

InitializeContext endp

Socket Initialization
Code: [Select]
InitializeSocket Proc USES ESI EDI pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED,pServer:PFASTSERVER
LOCAL numBytes:DWORD
MOV EDI,pContextKey
MOV ESI,pServer


MOV EDI,pContextKey
MOV InternetAddr.sin_addr, 0
invoke htons,0
MOV InternetAddr.sin_port, AX
MOV InternetAddr.sin_family, AF_INET
invoke bind,[EDI].CONTEXT_KEY.OvOut.socket,addr InternetAddr,sizeof InternetAddr
.if ConnectExPtr == NULL
invoke WSAIoctl,[EDI].CONTEXT_KEY.OvOut.socket,SIO_GET_EXTENSION_FUNCTION_POINTER,addr WSAID_CONNECTEX,sizeof WSAID_CONNECTEX,addr ConnectExPtr\
,sizeof ConnectExPtr,addr numBytes,NULL,NULL
.endif

invoke CreateIoCompletionPort,[EDI].CONTEXT_KEY.OvOut.socket, [ESI].FASTSERVER.hIOCompletionPort, pContextKey, NULL


ret

InitializeSocket endp

Socket Connection:
Code: [Select]
ConnectSocket Proc USES ESI EDI pContextKey:PCONTEXT_KEY,pOverlapped:POVERLAPPED

MOV EDI,pContextKey

invoke inet_addr,addr RemoteIPAddress
MOV InternetAddr.sin_addr, EAX
invoke htons,Port
MOV InternetAddr.sin_port, AX
invoke ConnectExFunc,[EDI].CONTEXT_KEY.OvOut.socket,addr InternetAddr,sizeof InternetAddr,NULL,NULL,NULL,addr [EDI].CONTEXT_KEY.OvOut
invoke GetLastError
.if EAX != ERROR_IO_PENDING
MOV EAX,SOCKET_ERROR
.endif
ret


ConnectSocket endp



felipe

  • Member
  • *****
  • Posts: 1249
  • Eagles are just great!
Re: IO Completion ports tracking multiple completion keys
« Reply #11 on: November 17, 2017, 07:52:28 AM »
Thanks for sharing your work frank, i guess you are telling the true.  :t

Welcome to the forum.  :redface:

 :P
Felipe.

AW

  • Member
  • *****
  • Posts: 2312
  • Let's Make ASM Great Again!
Re: IO Completion ports tracking multiple completion keys
« Reply #12 on: November 18, 2017, 12:35:00 AM »
This is a careless code dump.
When I post examples or code it is always complete and ready to be built, even when I don't leave attachments.
For me this subject is closed.

LiaoMi

  • Member
  • ****
  • Posts: 574
Re: IO Completion ports tracking multiple completion keys
« Reply #13 on: November 18, 2017, 01:13:30 AM »
Hi Frank,

this article will probably help you  ::) https://www.codeproject.com/Articles/10330/A-simple-IOCP-Server-Client-Class

Frank

  • Regular Member
  • *
  • Posts: 8
Re: IO Completion ports tracking multiple completion keys
« Reply #14 on: November 18, 2017, 05:50:31 AM »
This is a careless code dump.
When I post examples or code it is always complete and ready to be built, even when I don't leave attachments.
For me this subject is closed.

lol. Have you seen somebody post his whole project just for a question?
Take a look at stack overflow.
This isn't a code bank so why the hell would i need to post whole project just because small area doesn't work properly?
That is some bullshit there.