flat assembler
Message board for the users of flat assembler.

flat assembler > Windows > Picnic Playground

Author
Thread Post new topic Reply to topic
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
Chat is a very simple console application to provide a direct communication between two computers in the same peer to peer environment.
It uses UDP sockets, the winsock api and C library calls and is tested on Windows XP on my home network as my work also.
I had it unfinished on my hard disk for quite some time.

Command line parameters syntax like this: listen_port destination_machine destination_port

Example using hostnames.
on my laptop: chat 1024 desktop 1025
on my pc: chat 1025 laptop 1024

Example using IP address.
on my laptop: chat 1024 192.168.1.102 1025
on my pc: chat 1025 192.168.1.101 1024

Code:
;-------------------------------------------------------------------------
;   CHAT.ASM
;   Win32 Console Application
;-------------------------------------------------------------------------
;   Application uses the User Datagram Protocol (UDP)
;   to provide a direct communication between 2
;   computers in a peer to peer like environment.
;-------------------------------------------------------------------------
;   Fasm v1.69.20
;   20 Sep 2010, Picnic
;-------------------------------------------------------------------------

    format pe console
    entry main

    include "include\win32ax.inc"

section ".idata" import data readable writeable

    library\
    kernel32,"kernel32.dll",\
    user32,"user32.dll",\
    ws2_32,"ws2_32.dll",\
    msvcrt,"msvcrt.dll"

    include "include\api\kernel32.inc"
    include "include\api\user32.inc"

    import ws2_32,\
    gethostbyname,"gethostbyname",\
    gethostbyaddr,"gethostbyaddr",\
    WSAGetLastError,"WSAGetLastError",\
    WSAStartup,"WSAStartup",\
    WSACleanup,"WSACleanup",\
    closesocket,"closesocket",\
    inet_ntoa,"inet_ntoa",\
    inet_addr,"inet_addr",\
    recvfrom,"recvfrom",\
    sendto,"sendto",\
    socket,"socket",\
    listen,"listen",\
    bind,"bind",\
    htonl,"htonl",\
    htons,"htons",\
    ntohs,"ntohs"

    import msvcrt,\
    __getmainargs,"__getmainargs",\
    _beginthreadex,"_beginthreadex",\
    memset,"memset",\
    strcpy,"strcpy",\
    strlen,"strlen",\
    printf,"printf",\
    fgets,"fgets",\
    fflush,"fflush",\
    atoi,"atoi",\
    _iob,"_iob"

;-------------------------------------------------------------------------
;
section ".data" data readable writeable
;
;-------------------------------------------------------------------------

    MAX_SIZE = 2048
    INVALID_SOCKET = 0xFFFFFFFF
    crlf equ 0x0D,0x0A

    argc dd ?
    argv dd ?
    env dd ?
    listen_socket dd ?
    listen_port dd ?
    dest_port dd ?
    dest_name rb 256
    buffer rb MAX_SIZE

    align 4
    saddr sockaddr_in
    WSAData WSADATA

;-------------------------------------------------------------------------
;
section ".text" code readable executable
main:
;
;-------------------------------------------------------------------------

    cinvoke __getmainargs, addr argc, addr argv, addr env, 0
    .if ( dword [argc] = 4 )
        mov ebx, [argv]
        cinvoke atoi, dword [ebx+04h]
        mov dword [listen_port], eax
        push eax
        cinvoke atoi, dword [ebx+0Ch]
        mov dword [dest_port], eax
        pop ecx
    .endif

    ; Make sure data passed on command line is correct
    .if ( dword [argc] <> 4 | ~eax | ~ecx | eax > 65535 | ecx > 65535 | eax = ecx )
        cinvoke printf, <"Usage: chat [listen port] [destination machine] [destination port]",crlf>
        mov eax, 1
        ret
    .endif

    ; Save the destination machine's address/name
    cinvoke strcpy, addr dest_name, dword [ebx+08h]

    cinvoke printf, <"Initializing...",crlf>

    ; Starts the Winsock service
    invoke WSAStartup, 0202h, addr WSAData
    .if ( eax <> 0 )
        cinvoke printf, <"WSAStartup failed",crlf>
        mov eax, 1
        ret
    .endif

    ; Try to listen to requested port
    stdcall TryListen, dword [listen_port]
    .if ( ~eax )
        cinvoke printf, <"Error listening to port %d",crlf>, dword [listen_port]
        mov ebx, 1
    .else
        cinvoke printf, <"chat ready: <Ctrl-C> to exit",crlf>
        cinvoke fgets, addr buffer, MAX_SIZE, dword [_iob]

        .while ( eax <> 0 )
            ; Forward the sendbuf to destination machine
            ; Continue to grab input from stdin
            cinvoke strlen, addr buffer
            stdcall SendMsg, addr buffer, eax, addr dest_name, dword [dest_port]
            cinvoke fgets, addr buffer, MAX_SIZE, dword [_iob]
        .endw

        xor ebx, ebx
    .endif

    .if ( dword [listen_socket] <> INVALID_SOCKET )
        invoke closesocket, dword [listen_socket]
    .endif

    invoke WSACleanup
    invoke ExitProcess, ebx
    ret

;-------------------------------------------------------------------------
;
;   SendMsg()
;
;-------------------------------------------------------------------------

align 4
proc SendMsg uses ecx ebx edx,\
sendbuf:dword, sendlen:dword, host:dword, port:dword

    local ipaddr dd ?
    local to sockaddr_in

    ; Is the host passed a name?
    cinvoke atoi, dword [host]
    .if ( ~eax )
        invoke gethostbyname, [host]
    .else
        ; Otherwise, assume it's IP format
        cinvoke inet_addr, dword [host]
        mov dword [ipaddr], eax
        invoke gethostbyaddr, addr ipaddr, 4, AF_INET
    .endif

    .if ( ~eax )
        invoke WSAGetLastError
        cinvoke printf, <"Error getting host address - code: %ld",crlf>, eax
        xor eax, eax
        ret
    .endif

    virtual at eax
        .hostdata hostent
    end virtual
    mov eax, [.hostdata.h_addr_list]
    mov eax, [eax]
    mov eax, [eax]

    ; Endpoint address of the destination computer
    mov dword [to.sin_addr], eax
    mov dword [to.sin_family], AF_INET
    invoke htons, dword [port]
    mov word [to.sin_port], ax

    cinvoke printf, <"Message being sent to host %s port %d",crlf>, dword [host], dword [port]

    invoke sendto, dword [listen_socket], dword [sendbuf], dword [sendlen], 0, addr to, sizeof.sockaddr_in

    .if ( eax > dword [sendlen] | eax = INVALID_SOCKET )
        cinvoke printf, <"Error sending UDP packet from listen socket",crlf>
        xor eax, eax
        ret
    .endif

    mov eax, 1
    ret
endp

;-------------------------------------------------------------------------
;
;   TryListen()
;
;-------------------------------------------------------------------------

align 4
proc TryListen uses ecx ebx edx, port:dword

    local thread dd ?

    mov dword [listen_socket], INVALID_SOCKET

    ; This socket uses the User Datagram Protocol (UDP)
    invoke socket, AF_INET, SOCK_DGRAM, 17
    .if ( eax = INVALID_SOCKET )
        cinvoke printf, <"Error: listen socket creation failed",crlf>
        xor eax, eax
        ret
    .endif

    mov dword [listen_socket], eax

    mov dword [saddr.sin_family], AF_INET
    invoke htonl, 0 ; any address
    mov dword [saddr.sin_addr], eax
    invoke htons, dword [port]
    mov word [saddr.sin_port], ax

    invoke bind, dword [listen_socket], addr saddr, sizeof.sockaddr_in
    .if ( eax <> 0 )
        cinvoke printf, <"Error: bind on listen socket failed",crlf>
        invoke closesocket, dword [listen_socket]
        xor eax, eax
        ret
    .endif

    cinvoke _beginthreadex, 0, 0, addr ListenThread, dword [listen_socket], 0, addr thread
    .if ( ~eax )
        cinvoke printf, <"Error creating listen thread",crlf>
        xor eax, eax
        ret
    .endif

    invoke CloseHandle, eax

    mov eax, 1
    ret
endp

;-------------------------------------------------------------------------
;
;   ListenThread()
;
;-------------------------------------------------------------------------

align 4
proc ListenThread uses ecx ebx edx, s:dword

    local from_len dd ?
    local from sockaddr_in
    local recvbuf rb MAX_SIZE+100

    .while ( 1 )    ; loop forever

        mov [from_len], sizeof.sockaddr_in
        cinvoke memset, addr recvbuf, 0, MAX_SIZE
        invoke recvfrom, dword [s], addr recvbuf, MAX_SIZE-1, 0, addr from, addr from_len

        .if ( signed eax > 0 )

            lea ebx, dword [recvbuf]
            mov byte [ebx+eax], 0

            invoke inet_ntoa, dword [from.sin_addr]
            push eax
            movzx eax, word [from.sin_port]
            invoke ntohs, eax
            pop ecx

            cinvoke printf, <"Message received from host %s port %d",crlf>, ecx, eax
            cinvoke printf, ">> %s", addr recvbuf

        .endif

    .endw

    ret
endp
    


Last edited by Picnic on 29 Aug 2014, 20:54; edited 5 times in total
Post 20 Sep 2010, 20:29
View user's profile Send private message Reply with quote
Overflowz



Joined: 03 Sep 2010
Posts: 1047
Oh, so nice ! BTW can you write more simple code without command line args and without proc-s ? just like when conencted to wait for recive or send and client/server same like that. thank you! Smile
Post 21 Sep 2010, 11:20
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4160
Location: 2018
and for IRC?
Post 21 Sep 2010, 11:35
View user's profile Send private message Visit poster's website Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
Hi,

Overflowz, __getmainargs function provides a simple way to get the command line parameters.
As better alternatives see Windows API functions GetCommandLine or CommandLineToArgvW
Search fasm board for examples or even more simple winsock samples.

edfed i don't know much about IRC, never used it.
Post 22 Sep 2010, 11:26
View user's profile Send private message Reply with quote
Overflowz



Joined: 03 Sep 2010
Posts: 1047
Okay thanks. Smile I'm just stuck how to receive buffer and I know only send >.<
Post 22 Sep 2010, 12:55
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
A simple Winsock Multi-User Console Chat Server.
Made for Windows XP, tested with telnet.exe, putty client will also work.
It can handle backspace, users can change their names, it prints a user-list. Program is inspired from a C++ sample.
The listening port can be passed as a command line argument, the default port is 23. Esc stops the server.
Despite my lame code which is written in three days, it works well.

Image


Last edited by Picnic on 29 Aug 2014, 21:24; edited 2 times in total
Post 22 Jul 2012, 21:51
View user's profile Send private message Reply with quote
sleepsleep



Joined: 05 Oct 2006
Posts: 7516
Location: ˛                              ⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣ Posts: 6699
looks great!!
Post 23 Jul 2012, 00:40
View user's profile Send private message Reply with quote
bzdashek



Joined: 15 Feb 2012
Posts: 147
Location: Tolstokvashino, Russia
Yeah, wonderful!
Post 23 Jul 2012, 05:48
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
thank you both, appreciate the comments.
Post 24 Jul 2012, 05:06
View user's profile Send private message Reply with quote
bzdashek



Joined: 15 Feb 2012
Posts: 147
Location: Tolstokvashino, Russia
Where did the last version go?
Post 26 Aug 2012, 07:32
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
I thought to make it better, a login system with username and password for each account would be nice but to be honest i'm bored now. Feel free to modify source as you wish.
Ansi colors were added, exploited the fact that clients like telnet.exe are forgiving, and overlook that proper use requires an exchanging information first. Also a server log added.
Here you are, sorry for any inconvenience.


Silent Edit
I started re-writing the chat program. I upload new sources as soon as possible.

Image


Description:
Download
Filename: CHAT.zip
Filesize: 22.24 KB
Downloaded: 162 Time(s)



Last edited by Picnic on 29 Aug 2014, 20:49; edited 3 times in total
Post 26 Aug 2012, 10:44
View user's profile Send private message Reply with quote
bzdashek



Joined: 15 Feb 2012
Posts: 147
Location: Tolstokvashino, Russia
Thank you, Picnic!
Post 26 Aug 2012, 10:47
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
You're welcome bzdashek!


Last edited by Picnic on 03 Mar 2013, 19:55; edited 1 time in total
Post 12 Jan 2013, 16:24
View user's profile Send private message Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2910
Location: 0x77760000
When working on such projects consider using multi-threaded libraries with callback support (Windows has one for GUI but kind of sucks).

Example.

Make a library that can be re-used (duh)

Pseudo code
Code:

; import winsock

; Define our interface here. Just a struct

struct ISocketEvent
         onDataArrival   dd ? ; implement as proc onDataArrival, handle, lpData, dwSize
         onClientReady dd ? ; implement as proc onClientReady, handle, lpData, lpdwSize   ; return data to send and size in the last two parameters. (See below)
         onError           dd ? ; implement as proc onError, dwCode, pszDecription
         onConnect      dd ? ; implement as proc onConnect, handle, pszRemoteHost, dwPort
         onDisconnect   dd ? ; implement as proc onDisconnect, handle
ends

; Object identifiers
struct  SocketObject
          .socket   dd 0             ; socket handle
          .sai        sockaddr_in 
          .stop      dd 1             ; connection state (closed, this stops the loop)
          .ISocketEventPtr         ; the callback table pointer to user functions
endp


; impl

proc Startup
        ... winsock initialization here
endp 

/// Returns a handle (Basically a pointer to SocketObject struct)
proc Connect pszIP_or_DNS, port, iCallbackPtr

 
      handle =    memalloc SocketObject.Size

      handle.sai.port = port;
      handle.ISocketEventPtr = iCallbackPtr

      ... start connection thread
      CreateThread.. ConnectionThread, handle

      return handle
endp
proc ConnectionThread, handle
        ..winsock connection functions here


         handle.socket = socket(...);
           .. if error call  handle.ISocketEventPtr.onError, socket_error_code, "Custom or system description"

        .. if connection made
             call  handle.ISocketEventPtr.onConnect, handle, pszHostName, port
                          
             CreateThread( MonitorThread, handle )

       .. if not
             call handle.ISocketEventPtr.onError, socket_error_code, "Custom or system description"

       .. this thread exits
endp


/// Returns a handle (Basically a pointer to SocketObject struct)
proc Listen, port, iCallbackPtr
              handle = memalloc , SocketObject.Size

              handle.sai.port = port
              handle.ISocketEventPtr = iCallbackPtr

             // start listening thread
endp

proc ListenThread, handle
         while handle.stop = false
                 // you know the drill here boys
         end while
endp

proc MonitorThread, handle

      while handle.stop = false

      fd_set read_set.
      fd_set write_set.
      fd_set error_set.

      // check states here

      ..if(read_set)
         dwBytes = 0
         ioctlsocket(handle.socket, FIONREAD, dwBytes); .. available bytes to read
         
         buffer = memalloc dwBytes
         .. if not
             call handle.ISocketEventPtr.onError, custom_error_code, "Custom or system description"

         ..else
             recv(handle.socket, buffer, dwBytes)
             .. if not 
                 call handle.ISocketEventPtr.onError, socket_error_code, "Custom or system description"
             .. else
                 call handle.ISocketEventPtr.onDataAvailable, handle, buffer, dwBytes
                    if(buffer != null)    ; in case user did something stupid with the buffer
                         memfree(buffer)
                

      .. if(write_set)
          dwSize = 0
          lpBuffer= 0
          buffer = call handle.ISocketEventPtr.onClientReady, handle, buffer, dwSize

         if(buffer != null and dwSize > 0 )
            send(handle.socket, buffer, dwSize);

         .. if not
             call handle.ISocketEventPtr.onError, socket_error_code, "Custom or system description"

      if(error_set)
           get error code
            call handle.ISocketEventPtr.onError, socket_error_code, "Custom or system description"

      // check MSDN for more on how to check for a closed/disconnected socket
      if(read_set && <some other byte checks>)
           call handle.ISocketEventPtr.onDisconnected, handle
           exit here
           break;

         // pause or sleep here

      end while

        closesocket handle.socket
endp

proc FreeHandle, handle
         memfree, handle
endp

proc Close, handle
        handle.stop = true // this will stop the thread
endp

; exports

Startup
Connect
Listen
Send
Close
FreeHandle
    




Using it
Code:

; setup GUI
myGui.setup;

libSocket.Statup


proc onDataArrival, handle, bytes, size
         if(handle = my_handle)  ; of course you'd know how to do this
           myGui.RichEdit.Text.Append(bytes)
endp

proc onDisconnect
         myGui.Button.Connect.Enabled = true;
endp

my_handle dd 0
proc myGui.button.Connent.Click
          host = myGui.Edit.Host.Text
          port = int( myGui.Edit.Port.Text )
           my_handle = libSOcket.Connect, host, port
endp

    


Well that's about it. Sorry if it seems like nonsense but someone one day will find it useful. I'm currently developing on android and I'm using threads quite extensively so I often use interfaces to make things flow better other than having to wait for a function/method to return.
Post 13 Jan 2013, 00:35
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
@typedef no, it doesn't seem nonsense, suggestions and pseudocode are welcome.
I do have a multi-user chat program on which i used threads but is left unfinished.
I have little reusable code in asm, programs above are more like simple learning excercises, practicing C/C++ and asm simultaneously.
Post 15 Jan 2013, 12:40
View user's profile Send private message Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2910
Location: 0x77760000
Lol. No source code?

And what's up with the CryptXXX functions?
Post 05 Mar 2015, 02:07
View user's profile Send private message Reply with quote
catafest



Joined: 05 Aug 2010
Posts: 101
Windows defender see this like malware
Picnic wrote:
I thought to make it better, a login system with username and password for each account would be nice but to be honest i'm bored now. Feel free to modify source as you wish.
Ansi colors were added, exploited the fact that clients like telnet.exe are forgiving, and overlook that proper use requires an exchanging information first. Also a server log added.
Here you are, sorry for any inconvenience.


Silent Edit
I started re-writing the chat program. I upload new sources as soon as possible.

Image
Post 07 May 2017, 23:11
View user's profile Send private message Visit poster's website Yahoo Messenger Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1251
Location: Underwater
Unfortunately many of my fasm console programs that using sockets are recognized as viruses. I can not resolve this.
Post 09 May 2017, 06:46
View user's profile Send private message Reply with quote
catafest



Joined: 05 Aug 2010
Posts: 101
Picnic wrote:
Unfortunately many of my fasm console programs that using sockets are recognized as viruses. I can not resolve this.

I think the problem is the format of :
Code:
pe console    

, I don't have your source code for CHAT.rar
If you make a search on this forum will see how to fix that.
Nice ideea if you will update this with useful tools under Windows OS ...
Make a brainstroming about how can be usefull your application Smile
Post 09 May 2017, 10:59
View user's profile Send private message Visit poster's website Yahoo Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2018, Tomasz Grysztar.

Powered by rwasa.