Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

AHKsock - A simple AHK implementation of Winsock (TCP/IP)


  • Please log in to reply
179 replies to this topic
TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

Download
Last updated: January 19, 2011

AHKsock is a high-level wrapper which I have written to facilitate the use of the Winsock APIs in AHK. It will allow you to create clients and servers that can communicate with each other, purely written in AHK! The most important functions are:

 

AHKsock_Listen() - Starts listening on a port.
AHKsock_Connect() - Connects to a server.
AHKsock_Send() - Sends data to a connected socket.
AHKsock_Close() - Closes a connection.
AHKsock_GetAddrInfo() - Retrieves IP addresses from a hostname.
AHKsock_GetNameInfo() - Retrieves a hostname from an IP address.

 

Documentation

(Also found in AHKsock.ahk)

A few quick facts:

  • It is stdlib compatible.
  • There are no global variables.
  • The only supported protocol is TCP.I have tried to be as clear as possible when writing both the documentation and the examples. As a result, there is a lot to read, but it should explain the functioning of AHKsock well enough, even for a beginner. Start by running the examples and analyzing them to understand how to play around with the wrapper. If you have never used Winsock before, a very useful resource is this website, and this one, which have greatly helped me during research. Of course, MSDN is unavoidable.

Examples

These examples can all be tested on your own machine or LAN. I have also tested them over the Internet, and they all work fine. Note that Example 1 does not have a GUI. You must use a program like DebugView to see its output. Thanks to Lazslo for his useful Bin2Hex function included in this example. Also thanks to polyethene for his Anchor function included in Example 3. Example 2 requires the File library.

Example 1 - Simple Scenario - Client
Example 1 - Simple Scenario - Server
Example 2 - File Transfer - Client
Example 2 - File Transfer - Server - TransmitFile
Example 2 - File Transfer - Server - Single Client
Example 2 - File Transfer - Server - Multiple Client
Example 3 - Chatting
Example 4 - Hostname & IP Lookup

Comments and suggestions are always welcome!



tomoe_uehara
  • Members
  • 2166 posts
  • Last active: Jun 11 2015 05:33 PM
  • Joined: 05 Sep 2009
Hmmh.. Looks promising, I'll give it a try

franzk
  • Guests
  • Last active:
  • Joined: --
Hi

this looks interesting... could it be used to connect to an ftp client and monitor the output ?

Any change of a quick example ?

Thanks :)

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

Hmmh.. Looks promising, I'll give it a try

Please do!

could it be used to connect to an ftp client and monitor the output ?

FTP is an application layer protocol. AHKsock only takes care of the transport layer and under. At the application level, you can do whatever you want. In theory, if you can implement the FTP protocol yourself, then yes! But you're better off using the API functions already there for that.

franzk
  • Guests
  • Last active:
  • Joined: --
I have no idea how to do that :?

Thanks anyway :)

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
For create FTP terminal, WinInet can do good job, easyer than WinSock
<!-- m -->http://msdn.microsof...ibrary/aa384180<!-- m -->
<!-- m -->http://www.autohotke...pic.php?t=33506<!-- m -->
But I dunno if it's possible to have a progress bar...

edit: FTP HTTP download with progress bar (WinInet)
<!-- m -->http://www.autohotke...pic.php?t=45718<!-- m -->

edit2:
1/ Where do you have found value of SOMAXCONN = 0x7FFFFFFF
2/ DllCall("Ws2_32\freeaddrinfo", "uint", aiResult) it's free memory for real ? I don't know why but don't work in my project...
3/ your sockaddr is at NumGet(aiResult+0,24), it points value of memory address of sockaddr ? I worked with NumGet(aiResult+0,40) for IpV4
sorry for question I don't understand all your script.

  • Guests
  • Last active:
  • Joined: --
In the chat example, in what format is the data received?

If I put "Tooltip, %ptrText%" immediately after the "SendMessage, 0x00C2, False, ptrText,, ahk_id %hEdit% ;EM_REPLACESEL" all I get is the same 8 digit number repeated over and over as my Tooltip, yet the chat window shows the actual data.

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

In the chat example, in what format is the data received?

If I put "Tooltip, %ptrText%" immediately after the "SendMessage, 0x00C2, False, ptrText,, ahk_id %hEdit% ;EM_REPLACESEL" all I get is the same 8 digit number repeated over and over as my Tooltip, yet the chat window shows the actual data.

ptrText is a pointer to the text.
Try this:
ToolTip, % DllCall("MulDiv", "int", ptrText, "int", 1, "int", 1, "str")


hughman
  • Members
  • 192 posts
  • Last active: Feb 14 2016 06:59 AM
  • Joined: 11 Feb 2007
Good comments and docs, I like it.
Do you have a plan to make it support UDP?

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

Good comments and docs, I like it.
Do you have a plan to make it support UDP?

Eventually, yes. But I plan on adding security features and IPv6 first.

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

edit2:
1/ Where do you have found value of SOMAXCONN = 0x7FFFFFFF
2/ DllCall("Ws2_32\freeaddrinfo", "uint", aiResult) it's free memory for real ? I don't know why but don't work in my project...
3/ your sockaddr is at NumGet(aiResult+0,24), it points value of memory address of sockaddr ? I worked with NumGet(aiResult+0,40) for IpV4
sorry for question I don't understand all your script.

Sorry for the late reply! I hadn't noticed your edit.

1. It's defined in WinSock2.h
2. freeaddrinfo doesn't return an error code if it fails, but aiResult IS a pointer to the linked list, so it should be working.
3. If you look at the addrinfo struct, you can see that the *ai_addr member is at offset 24. Where did you get 40? addrinfo is only 32 bytes long.

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
Thanks for reply :)

1/ somaconn
I found Somaxconn = 5 (#define) in this doc <!-- m -->http://www.sockets.com/winsock.htm<!-- m -->
I'm not a programmer so dunno if "SOMAXCONN" string work with AHK and haven't acces to WinSock2.h ( or how do it )

2/&3/ freeaddrinfo it's strange, I check with a numget loop, it's free memory of sockaddr but not the strange pointer, but I haven't recheck ( perhaps my fault with logic error )
IPAddress = www.google.com 
Port = 80 ; it's an option 

; ... WSAStartUp ... 

VarSetCapacity(mask, 256, 0) ; it's an option, you select ipv4 or ipv6 for return of numeric address 
NumPut(2, mask, 4, "Short") ; 2 = ipv4  23 = ipv6 
VarSetCapacity(Result, 256, 0) 
msgbox % DllCall("Ws2_32\getaddrinfo", "Str", IPAddress, "Str", Port, "UInt", &mask, "UInt", &Result) " GetAddrInfo " 

msgbox % DllCall("Ws2_32\WSAGetLastError") " Error " 

;DllCall("Ws2_32\"GetAddrInfo", ... , "UInt*", Result) / ... , "UInt", &Result)
;msgbox % DllCall("Ws2_32\freeaddrinfo", "UInt *", Result) 
;msgbox % DllCall("Ws2_32\freeaddrinfo", "UInt", Result) 
;msgbox % DllCall("Ws2_32\freeaddrinfo", "UInt", &Result) 

loop 256 ; just for check Value, they parse value of structure in other structure ( ref table at bottom ) 
msgbox % NumGet(NumGet(Result, 0, "UInt")+a_index-1, 0, "UChar") " AddrInfo Result " a_index-1 

; 0 -> 4 = allready an numeric address 
; 4 -> 2 = ipv4 , 23 = ipv6 
; 16 - > len (v4=16 v6=28) 
; 24 to 39> ???? canon name ? can't have a good translation of this in french
; 40 -> begin of sockaddr: 2 = ipv4 , 23 = ipv6 
; 42 to 44 -> port 
; 44 to 47 -> numeric address returned (if ipv4) 
; 48 to 63 -> numeric address returned (if ipv6)

BUT I think to understand my error now

Edit: I have understand my mistake :)
Here the code who helped me, it's +24 , but +40 work but very hazardous because it works only if they are memory after addr_info (we can view this coincidence with offset value)...

Thanks again, I do Ipv6 in my script, consider this like a render thanks :)

IPAddress = www.google.com
;Port = 8765 ;option

VarSetCapacity(wsaData, 32, 0)
DllCall("Ws2_32\WSAStartup", "UShort", 0x0202, "UInt", &wsaData)

VarSetCapacity(mask, 32, 0)
NumPut(2, mask, 4, "Short")
DllCall("Ws2_32\getaddrinfo", "Str", IPAddress, "Str", Port, "UInt", &mask, "UInt*", Result)

log := Result "`tADRRINFO"
log .= "`n+0`tai_flags = " NumGet(Result+0)
log .= "`n+4`tai_family = " NumGet(Result+4)
log .= "`n+8`tai_socktype = " NumGet(Result+8)
log .= "`n+12`tai_protocol = " NumGet(Result+12)
log .= "`n+16`tai_addrlen = " NumGet(Result+16)
log .= "`n+24`tai_addr = " NumGet(Result+24)

log .= "`n`n"NumGet(Result+24) "`tSOCKADDR (IPV4)"
log .= "`n+0`tsin_family = " NumGet(NumGet(Result+24, 0, "UInt"), 0, "Short")
log .= "`n+2`tsin_port = " DllCall("Ws2_32\htons", "UShort", NumGet(NumGet(Result+24, 0, "UInt"), 2, "UShort") )

log .= "`n+4`tsin_address = " NumGet(NumGet(Result+24, 0, "UInt"), 4, "UChar")
loop 3
log .= "." NumGet(NumGet(Result+24, 0, "UInt"), 4+a_index, "UChar")

DllCall("Ws2_32\freeaddrinfo", "UInt", Result)
msgbox % log

VarSetCapacity(mask, 32, 0)
NumPut(23, mask, 4, "Short")
DllCall("Ws2_32\getaddrinfo", "Str", IPAddress, "Str", Port, "UInt", &mask, "UInt*", Result)

log := Result "`tADRRINFO"
log .= "`n+0`tai_flags = " NumGet(Result+0)
log .= "`n+4`tai_family = " NumGet(Result+4)
log .= "`n+8`tai_socktype = " NumGet(Result+8)
log .= "`n+12`tai_protocol = " NumGet(Result+12)
log .= "`n+16`tai_addrlen = " NumGet(Result+16)
log .= "`n+24`tai_addr = " NumGet(Result+24)

log .= "`n`n"NumGet(Result+24) "`tSOCKADDR (IPV6)"
log .= "`n+0`tsin_family = " NumGet(NumGet(Result+24), 0, "Short")
log .= "`n+2`tsin_port = " DllCall("Ws2_32\htons", "UShort", NumGet(NumGet(Result+24), 2, "UShort"))

SetFormat, IntegerFast, Hex
IPV6 := DllCall("Ws2_32\htons", "UShort", NumGet(NumGet(Result+24), 8, "UShort"))
loop 7
IPV6 .= ":" DllCall("Ws2_32\htons", "UShort", NumGet(NumGet(Result+24), 8+a_index*2, "UShort"))
SetFormat, IntegerFast, Dec
StringReplace, IPV6, IPV6, 0x, , All
log .= "`n+8`tsin_address = " IPV6

DllCall("Ws2_32\freeaddrinfo", "UInt", Result)
msgbox % log

DllCall("Ws2_32\WSACleanup")
return

;IPAddress = 0:0:0:0:0:0:0:1 
;IPAddress = 127.0.0.1 
;Port = 8765 

;StringReplace, IPAddress, IPAddress, :, :, UseErrorLevel 
;IPver := ( errorlevel = 7 ) ? 23 : 2

;VarSetCapacity(sockaddr, 128, 0) 
;  NumPut(IPver, sockaddr, 0, "Short") 
;  NumPut(DllCall("Ws2_32\htons", "UShort", Port), sockaddr, 2, "UShort") 
;if IPver = 2 
;  NumPut(DllCall("Ws2_32\inet_addr", "Str", IPAddress), sockaddr, 4) 
;if IPver = 23 
;  Loop, Parse, IPAddress, : 
;    NumPut(DllCall("Ws2_32\htons", "UShort", "0x" . a_loopfield ), sockaddr, (a_index*2)-2+8, "UShort")


Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
Other things, your library is hard to understand BUT VERY GOOD DOCS, perhaps create internal function like getaddrinfo with hints in params and build after this sockaddress strutur, many part of code is duplicated and will be easy for you to implement other protocol...

I don't know... I work in similar project, maybe we can help each other
<!-- m -->http://www.autohotke...pic.php?t=57306<!-- m -->

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

1/ somaconn
I found Somaxconn = 5 (#define) in this doc <!-- m -->http://www.sockets.com/winsock.htm<!-- m -->

Yes, SOMAXCONN is indeed defined as 5 in WinSock.h, but as 0x7FFFFFFF in WinSock2.h.

I'm not a programmer so dunno if "SOMAXCONN" string work with AHK and haven't acces to WinSock2.h ( or how do it )

You can have access to the header files if you download the Windows SDK.

Other things, your library is hard to understand BUT VERY GOOD DOCS, perhaps create internal function like getaddrinfo with hints in params and build after this sockaddress strutur, many part of code is duplicated and will be easy for you to implement other protocol...

Good idea! I might do this in the next release.

I don't know... I work in similar project, maybe we can help each other
<!-- m -->http://www.autohotke...pic.php?t=57306<!-- m -->

I replied to you there.

horntail
  • Members
  • 69 posts
  • Last active: Jul 19 2010 06:20 PM
  • Joined: 03 Aug 2009
Ive noticed during testing that the recv() function in the example clients is receiving an sEvent of "SEND" when the clients ive looked at do not appear to handle this value, i think its something to do with the code from AHKsock below:

%sFunc%("SEND", wParam, AHKsock_Sockets("GetName", wParam)
                                      , AHKsock_Sockets("GetAddr", wParam)
                                      , AHKsock_Sockets("GetPort", wParam))

the examples worked a few days ago but now they just dont