TCP/UDP Connections

Started by theunknownguy, March 25, 2010, 12:03:16 AM

Previous topic - Next topic

theunknownguy

Here is some easy to use "kind of" library for connect into any client (internal ones) since it follow the Window messages based connection (it isnt recommended for complex taks), instead of that use IOCP.

But anyway here is for Wnd MSG, you just set the information in the structure and call the procedures with the arguments:


                                   ;///////////////////////////////////
                                   ;       WinSock releated
                                   ;///////////////////////////////////

.const
MAX_BUFF_LENGTH equ 4000 ;Do not change

WSABUF Struct
len DWord ? ;len of buffer
buffer DWord ? ;pointer to buffer
WSABUF EndS

InternalClients_Struct Struct
TCPorUDP Dword ? ;Connection Model
Port Dword ? ;Port for connection
IPorName DB 20 Dup(?) ;IP or Host name
hWnd DWord ? ;Handler of WndProc
MSGID Dword ? ;ID for WSAAsynSelect
Sock DWord ? ;Var for socket
SockAddr sockaddr_in <>
SendBuff DB MAX_BUFF_LENGTH Dup(?) ;Buffer for send bytes, dont change this constant
RecvBuff DB MAX_BUFF_LENGTH Dup(?) ;Buffer for recv bytes, dont change this constant
SendBuffSize DWord ? ;If we want to use less bytes for buffer without changing the constant
RecvBuffSize DWord ? ;If we want to use less bytes for buffer without changing the constant
pSendPacket Dword ? ;Variable for hold the pointer to the last packet that couldt been sended caused WSAEWOULDBLOCK
LastLengthPacket Dword ? ;Variable for hold the last length of the packet that couldt been sended caused WSAWOULDBLOCk
ProtocolAddr Dword ? ;Pointer to protocol for handle packets
Connected DWord ? ;Its Connected sock or dont
InternalClients_Struct EndS


V_Sock_CreateSocket Proto :Dword
V_Sock_MakeAddr Proto :Dword, :Dword

.Const
.Data?
.Data
.Code

V_Sock_SetAll Proc uses ecx
Local pWSADATA:WSADATA ;Point to local struct
assume ecx:ptr InternalClients_Struct
Invoke WSAStartup, 202H, Addr pWSADATA
.If (Eax != 0)
  RGB 255, 127, 80 ;Coral (orange ligth)
  invoke vprint, $CTA0("SockInteral:\] Error on while loading WSA"), eax
  xor eax, eax
.else
  mov edx, Dword ptr pWSADATA
  and edx, 0FFFFh ;Word
  .if (edx == 2) ;Check version high byte
    mov edx, Dword ptr pWSADATA
    and edx, 0FFFFh ;Word
    shr edx, 8
    and edx, 0FFh ;Byte
    .if (edx == 2) ;Check version low byte
push ecx ;Save struct
invoke V_Sock_CreateSocket, [ecx].TCPorUDP ;Create a socket
.if (eax == NULL)
RGB 255, 64, 64 ;Coral (orange ligth)
invoke vprint, $CTA0("SockInteral:\] Error while creating Socket"), eax
xor eax, eax
.else
invoke V_Sock_MakeAddr, [ecx].IPorName, [ecx].Port ;Convert IP or HOST name into internet address
.if (eax == NULL)
   RGB 255, 64, 64 ;Coral (orange ligth)
   invoke vprint, $CTA0("SockInteral:\] Error while resolving Address"), eax
   xor eax, eax
.else
   call V_Sock_Connect ;Connect
   .if (eax == NULL)
     RGB 255, 64, 64 ;Coral (orange ligth)
     invoke vprint, $CTA0("SockInteral:\] Error while trying to connect to port:[%d]"), eax, [ecx].Port
     xor eax, eax
   .endif
.endif
.endif
    .else
      RGB 255, 64, 64 ;Coral (orange ligth)
      invoke vprint, $CTA0("SockInteral:\] WSA Version its 2.[%d], please use 2.2"), eax, edx
    .endif
  .else
    RGB 255, 64, 64 ;Coral (orange ligth)
    invoke vprint, $CTA0("SockInteral:\] WSA Version its too old, please use 2.2"), eax
  .endif
.endif
pop ecx ;Return struct
.if (eax == NULL)
  call V_Sock_Close ;Close if something went wrong
  xor eax, eax
.endif
Ret
V_Sock_SetAll EndP

V_Sock_Send Proc Uses Ecx pPacket:DWord, PacketLength:DWord
Local MyStruct:DWord
Local BytesSend:DWord
Local ExtraBytes:DWord
Mov MyStruct, Ecx
Mov ExtraBytes, 0
Mov BytesSend, 0
Assume Ecx:Ptr InternalClients_Struct
mov eax, pPacket
mov edx, PacketLength
mov [ecx].pSendPacket, eax ;Save in case that we cant send the packet, caused WSAEWOULDBLOCK
mov [ecx].LastLengthPacket, edx ;Save in case that we cant send the packet, caused WSAEWOULDBLOCK
.If (edx == 0) ;If packet length its  0
    RGB 255, 64, 64
    invoke vprint, $CTA0("SockInteral:\] Trying to send a NULL packet"), eax
Xor Eax, Eax
.Elseif ([Ecx].Connected == 0) ;If we arent connected
     RGB 255, 64, 64
     invoke vprint, $CTA0("SockInteral:\] You arent connected to the internal client for send"), eax
Xor Eax, Eax
.Elseif (PacketLength > MAX_BUFF_LENGTH) ;If more than max buffer length
     RGB 255, 64, 64
     invoke vprint, $CTA0("SockInteral:\] The packet exceed the MAX_BUFFER_LENGTH constant"), eax
Xor Eax, Eax
.Else
   .Repeat
Mov Eax, PacketLength
    Mov Edx, pPacket
    Add Edx, ExtraBytes ;Packet + ExtraBytes if they are
    Sub Eax, ExtraBytes ;PacketLength - ExtraBytes = NewPacketLength (if there are extra bytes)
Invoke send, [Ecx].Sock, Edx, Eax, NULL
Mov Ecx, MyStruct
Mov BytesSend, Eax
.If (Eax == -1)
Invoke WSAGetLastError
.If (Eax != WSAEWOULDBLOCK) ;If connection is busy
            RGB 255, 64, 64
            invoke vprint, $CTA0("SockInteral:\] Connection busy for send, will resend when ready"), eax
mov eax, 2
.Else
            mov edx, eax
            RGB 255, 64, 64
            invoke vprint, $CTA0("SockInteral:\] Error when sending [%d]"), eax, edx
Xor Eax, Eax
        .Endif
    .Else
      Mov Eax, PacketLength
      .If (BytesSend != Eax) ;If not all the bytes where sended
         Mov Edx, BytesSend
         Add ExtraBytes, Edx
      .Else
            mov eax, 1
          .Endif
    .Endif
   .Until (ExtraBytes == 0)
.Endif
.if (eax == 1) || (eax == 0) ;If all went OK or a error happend
  invoke V_ZeroBuff, Addr InternalPacket, MAX_PACKETSEND_LENGTH ;Clean the packet buffer
.else ;If WSAEWOULDBLOCK then i dont clean the packet buffer
.endif
Assume Ecx:Nothing
Ret
V_Sock_Send EndP


V_Sock_Recv Proc
Local MyStruct:DWord
Local BytesRecv:DWord
Local RecvPacketLength:DWord
Local RecvPacketHeader:Dword
Local localExtraBytes:DWord
.data
ExtraBytes DD ? ;Extra bytes in global mode
.code
Mov localExtraBytes, 0
mov RecvPacketLength, 0
Mov MyStruct, Ecx
Assume Ecx:Ptr InternalClients_Struct
lea edx, [ecx].RecvBuff
add edx, ExtraBytes ;If there are extra bytes
Invoke recv, [Ecx].Sock, edx, [ecx].RecvBuffSize, 0
Mov BytesRecv, Eax
.If (Eax == 0)
    RGB 255, 64, 64
    invoke vprint, $CTA0("SockInteral:\] Error no bytes recv"), eax
    mov eax, -1
.ElseIf (Eax == -1)
Invoke WSAGetLastError
.If (Eax == WSAEWOULDBLOCK) ;if connection is busy
      RGB 255, 64, 64
      invoke vprint, $CTA0("SockInteral:\] Connection busy to recv, we will recv later"), eax
      mov eax, 1 ;We will try later to recv
    .Else
      RGB 255, 64, 64
      invoke vprint, $CTA0("SockInteral:\] Internal error while recv"), eax
      mov eax, -1
    .EndIf
.Else
Mov Ecx, MyStruct
.If (BytesRecv > 3) ;if less than 3 bytes
       RGB 255, 64, 64
       invoke vprint, $CTA0("SockInteral:\] Error, less than 3 bytes recv"), eax
       mov eax, -1
.Else
CheckC1orC2:
      Mov Edx, localExtraBytes
    Movsx eax, Byte Ptr [[Ecx].RecvBuff + Edx]
    .If (Al == 0C1H)
  Xor Eax, Eax
  Mov Edx, localExtraBytes
  Movsx eax, Byte Ptr [[Ecx].RecvBuff + Edx + 1]
  Mov RecvPacketLength, Eax
  Movsx eax, Byte Ptr [[Ecx].RecvBuff + Edx + 2]
  Mov RecvPacketHeader, eax
    .ElseIf (Al == 0C2H)
  Mov Edx, localExtraBytes
  Xor Eax, Eax
  Xor Ebx, Ebx
  Movsx eax, Byte Ptr [[Ecx].RecvBuff + Edx + 1]
  Shl Eax, 8
  Movsx ebx, Byte Ptr [[Ecx].RecvBuff + Edx + 2]
          Or Eax, Ebx
          Mov RecvPacketLength, Eax
          Movsx eax, Byte Ptr [[Ecx].RecvBuff + Edx + 3]
  Mov RecvPacketHeader, eax
        .Else
          RGB 255, 64, 64
          invoke vprint, $CTA0("SockInteral:\] Invalid packet header"), eax
          mov ExtraBytes, 0
          mov eax, -1
          jmp EndRecv
        .EndIf
        .If (RecvPacketLength == 0) ;If packet length its 0
           RGB 255, 64, 64
           invoke vprint, $CTA0("SockInteral:\] Invalid length of packet"), eax
           mov ExtraBytes, 0
           mov eax, -1
        .Else
      Mov Ecx, MyStruct
      Mov Edx, RecvPacketLength
      .If (Edx <= BytesRecv) ;If the byte of packet is less or equal than the recived bytes
      Xor Ebx, Ebx
      Lea Edx, [Ecx].ProtocolAddr
    Lea Eax, [Ecx].RecvBuff
    Add Eax, localExtraBytes
    Mov ebx, RecvPacketHeader
    Push RecvPacketLength
    Push Eax ;RecvBuffer
    Push Ebx ;PacketHeader
    Call Edx ;call Protocol core depending of the struct used
    Mov Ecx, MyStruct
    Mov Edx, RecvPacketLength
    Add localExtraBytes, Edx
    Sub BytesRecv, Edx
    .If (BytesRecv < 0) ;if still bytes that we havent readed
    Jmp CheckC1orC2
CheckLoop:
    .Else
    mov ExtraBytes, 0 ;I make sure to set this
                mov eax, 1
    .EndIf
          .Else ;If byte packet of length says there still more bytes that the ones we actual recieve
             mov edx, BytesRecv
             add ExtraBytes, edx ;Save to global counter
             xor eax, eax
          .Endif
        .Endif
    .EndIf
.EndIf
EndRecv:
.if (eax == -1) ;If some error has happen
   mov ecx, MyStruct
   invoke V_ZeroBuff, [ecx].RecvBuff, [ecx].RecvBuffSize ;Clean the buffer
.elseif (eax == 1) ;If we end succesfull reading the packet
   mov ecx, MyStruct
   invoke V_ZeroBuff, [ecx].RecvBuff, [ecx].RecvBuffSize ;Clean the buffer
.else ;If we expecting to link the next packet comming to the current we dont clean the buffer
.endif
Assume Ecx:Nothing
Ret
V_Sock_Recv EndP

;/////////////////////////////////////////
;Create Socket
;////////////////////////////////////////
V_Sock_CreateSocket Proc Uses Ecx UDPorTCP:Dword
assume ecx:ptr InternalClients_Struct
.If (UDPorTCP == 1) ;UDP
  Mov Eax, SOCK_DGRAM
.Else
  Mov Eax, SOCK_STREAM
.EndIf
Lea Ecx, [Ecx].Sock
Push Ecx
Invoke socket, AF_INET, Eax, IPPROTO_IP
Pop Ecx
.If (Eax == -1)
    mov dword ptr [ecx], eax ;Unvalid Socket
    xor eax, eax
.Else
    Mov DWord Ptr [Ecx], Eax ;Save socket in struct
.EndIf
Assume Ecx:Nothing
Ret
V_Sock_CreateSocket EndP

;///////////////////////////////////////////////////////
;Connect procedure
;///////////////////////////////////////////////////////
V_Sock_Connect Proc uses ecx
assume ecx:ptr InternalClients_Struct
push ecx
Invoke connect, [Ecx].Sock, addr [Ecx].SockAddr, SizeOf sockaddr_in
pop ecx
.If (Eax == -1)
    Invoke WSAGetLastError
.If (Eax != WSAEWOULDBLOCK)
    Xor Eax, Eax
.else
        push ecx
Invoke WSAAsyncSelect, [Ecx].Sock, [ecx].hWnd, [ecx].MSGID, FD_READ + FD_CLOSE
        pop ecx
.If (Eax == -1)
   Xor Eax, Eax
.Else
   Mov [Ecx].Connected, 1 ;Already connected
.EndIf
     .endif
.endif
Assume Ecx:Nothing
Ret
V_Sock_Connect EndP

;/////////////////////////////////////////////////////////
;Custom proc for make an Host address from input arguments
;and save the address in UDP struct
;RETURN VALUES: 1 == SUCCESS, 0 == FAILURE
;/////////////////////////////////////////////////////////
V_Sock_MakeAddr Proc Uses Ecx IPorName:DWord, Port:DWord
Local MyStruct:DWord
assume ecx:ptr InternalClients_Struct
lea ecx, [ecx].SockAddr
Assume Ecx:Ptr sockaddr_in
Push Ecx
Invoke ntohs, Port
Pop Ecx
Mov [Ecx].sin_family, 2
Mov [Ecx].sin_port, Ax
push ecx
Invoke inet_addr, IPorName ;Take by IP
pop ecx
Mov [Ecx].sin_addr, Eax
mov MyStruct, ecx ;Save for now struct in a variable
.If (Eax == -1)
Invoke gethostbyname, IPorName ;Take by Host Name
  .If (Eax == 0)
  .Else
     Assume Eax:Ptr hostent
     Mov Ecx, MyStruct
      Mov Edx, DWord Ptr [Eax].h_list
      Mov Ebx, [Edx] ;EBX = Host name converted
     Invoke MemCopy, Ebx, Addr [Ecx].sin_addr, [Eax].h_len ;Save into sin_addr in our struct
  .EndIf
.EndIf
Assume Ecx:Nothing
assume eax:Nothing
Ret
V_Sock_MakeAddr EndP

;/////////////////////////////////////////
;Close socket
;////////////////////////////////////////
V_Sock_Close Proc Uses Ecx
Assume Ecx:Ptr InternalClients_Struct
Push Ecx
Invoke shutdown, [Ecx].Sock, NULL
Pop Ecx
Push Ecx
Invoke closesocket, [Ecx].Sock
Pop Ecx
Mov [Ecx].Sock, -1
Mov [Ecx].Connected, 0
Assume Ecx:Nothing
Ret
V_Sock_Close EndP


The code is tested under 5-6 internal clients under UDP some and others in TCP connection with no problems. (I use it on a game emulator)

The procedures like Recv and Send are customed for handle UDP and TCP at the same time.

Also the procedure Recv is made for a custom packet system based on this:

C1 -> Main Header
XX -> Lenght of packet
XX -> Header
XX -> SubHeader
[XX XX XX] -> Extra data


Ignore the Vprint procedure is just to print for window, you can remove if you like.  :cheekygreen:

Hope it helps somebody  :U