Jump to content


Photo

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


  • Please log in to reply
162 replies to this topic

#1 TheGood

TheGood
  • Members
  • 589 posts

Posted 17 May 2010 - 06:23 PM

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 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!



#2 tomoe_uehara

tomoe_uehara
  • Members
  • 2077 posts

Posted 17 May 2010 - 06:34 PM

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

#3 franzk

franzk
  • Guests

Posted 17 May 2010 - 09:59 PM

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 :)

#4 TheGood

TheGood
  • Members
  • 589 posts

Posted 17 May 2010 - 10:15 PM

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.

#5 franzk

franzk
  • Guests

Posted 18 May 2010 - 06:27 AM

I have no idea how to do that :?

Thanks anyway :)

#6 Zaelia

Zaelia
  • Members
  • 707 posts

Posted 18 May 2010 - 12:34 PM

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.

#7 Guests

  • Guests

Posted 19 May 2010 - 01:14 AM

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.

#8 TheGood

TheGood
  • Members
  • 589 posts

Posted 19 May 2010 - 03:36 AM

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")


#9 hughman

hughman
  • Members
  • 189 posts

Posted 19 May 2010 - 06:13 AM

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

#10 TheGood

TheGood
  • Members
  • 589 posts

Posted 19 May 2010 - 02:21 PM

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.

#11 TheGood

TheGood
  • Members
  • 589 posts

Posted 19 May 2010 - 03:27 PM

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.

#12 Zaelia

Zaelia
  • Members
  • 707 posts

Posted 19 May 2010 - 04:25 PM

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")


#13 Zaelia

Zaelia
  • Members
  • 707 posts

Posted 19 May 2010 - 09:02 PM

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 -->

#14 TheGood

TheGood
  • Members
  • 589 posts

Posted 20 May 2010 - 01:29 AM

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.

#15 horntail

horntail
  • Members
  • 69 posts

Posted 23 May 2010 - 03:23 PM

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