Jump to content

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

About Winsock and TCP/IP


  • Please log in to reply
36 replies to this topic
Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
@TheGood
Thanks for suggestion, I take large size for variable for test, in fact I can decrease this, and I have already did errors with structur and too high variable :(
OutPutdebug can do a well job, but I already made my bad habits :)
About WSAerror I discard it for to have a small readable script, but I work with it. Look at all the exceptions and errors takes more time than the program itself, it's just a personal choice to discard errors in the final script.

VarSetCapacity(wsaData, 1024, 0)
DllCall("Ws2_32\WSAStartup", "UShort", 0x0202, "UInt", &wsaData)
log := NumGet(wsaData) "`tWSADATA"
log .= "`n+0`tCurrentVersion = "NumGet(wsaData, 0, "UChar") "." NumGet(wsaData, 1, "UChar")
log .= "`n+2`tHighVersion = "NumGet(wsaData, 2, "UChar") "." NumGet(wsaData, 3, "UChar")
log .= "`n+4`tDescription = " Chr(NumGet(wsaData, 4, "UChar"))
loop 10
log .= Chr(NumGet(wsaData, 4+a_index, "UChar"))
log .= "`n+260`tSystemStatus = " Chr(NumGet(wsaData, 260, "UChar"))
loop 7
log .= Chr(NumGet(wsaData, 260+a_index, "UChar"))
msgbox % log

@Z_Gecko
The German forum always amazes me to have new things like this, I never think to look on this forum with the language barrier ... Thank you to show me this script!
Regarding the script, I'll learn on the use of recfrom () and ioctlsocket (), but using SetTimer, Recv, 200 loose all interest in the UDP :( (but very good for local network , broadcoast option for ipv4 )


The Problem with recvfrom() he don't "free" the recv buffer (recv() do this ) , and after this, WSAAsync receiv in loop a FD_read message... So we need to work on it for use a real-time UDP protocol.

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
I don't understand why, but it's work...
So we have a real-time messenger in UDP protocol (not a SetTimer, using WSAAsync), and I use only one socket for send and receive data (can be an advantage or a problem). However I need more feedback and experience , I haven't test it with multi computer, and the script in german forum use option broadcast for send and show local IPv4 with 2 socket ( send & recv )...

note: Diff between "client" and UDP "server" it's just the bind function... and if recvfrom() works well we can do ping/pong message, it's unidirectional but we can "rethrow", for have something like a TCP we need to merge client/server UDP in the same script, so it's not design for don't touch firewall or router... or Server must send message very often to client...

WinsockMessage(socket, event)
{
Critical
global log

VarSetCapacity(recvdata, 256, 0)
  VarSetCapacity(recvaddr, 32) 
  [color=red]VarSetCapacity(FromBufferLength, 64)[/color]
ret := DllCall("Ws2_32\recvfrom", "UInt", socket, "Str", recvdata, "UInt", 256, "UInt", 0, "UInt", &recvaddr, [color=red]"UInt", &FromBufferLength[/color]) 
log .= "`nRecv: " recvdata " / error:" DllCall("Ws2_32\WSAGetLastError") "/ event:" event "/ socket:" socket "/ return:" ret " / fromIP:"
log .= NumGet(recvaddr, 4, "UChar") 
loop 3
log .= "." NumGet(recvaddr, 4+A_Index, "UChar")

; check
;log .= "`n" NumGet(recvaddr, 0, "UChar")
;loop 32
;log .= "_" NumGet(recvaddr, A_Index, "UChar")
;log .= "`n" NumGet(FromBufferLength, 0, "UChar")
;loop 64
;log .= "_" NumGet(FromBufferLength, A_Index, "UChar")

Guicontrol,, LogEdit, %log%
controlsend, edit1, ^{end}, Tiny UDP
}


Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
I rewrote the UDP script for broadcast(local network):
- WSAASyncSelect create a "real-time" with UDP
- two sockets ( for to receiv and to send) is better
- script can send one message to a specified address
- display the connection/disconnection

It seems that the broadcast feature is only for IPV4 :( and this script is for run one time per computer ( can't recreate the same socket at same address:port )
Sorry to pollute the forum is a bit like a log, but I think this script can be usefull for network admin

Port = 8787 ; choice a port

Gui, Add, Edit, w320 r10 vLogEdit ReadOnly,
Gui, Add, Edit, section w200 R1 Limit255 vsenddata,
Gui, Add, Button, ys gSendButton, Send
Gui, Show,, Tiny UDP
OnExit, ExitSub

; ----------------------------------------------------------------

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

recvsock := DllCall("Ws2_32\socket", "Int", 2, "Int", 2, "Int", 17)
VarSetCapacity(recvaddr, 32, 0)
NumPut(2, recvaddr, 0, "Short")
NumPut(DllCall("Ws2_32\htons", "UShort", Port), recvaddr, 2, "UShort")
DllCall("Ws2_32\bind", "UInt", recvsock, "UInt", &recvaddr, "Int", 32)

sendsock := DllCall("Ws2_32\socket", "Int", 2, "Int", 2, "Int", 17)
VarSetCapacity(toaddr, 32, 0)
NumPut(2, toaddr, 0, "Short")
NumPut(DllCall("Ws2_32\htons", "UShort", Port), toaddr, 2, "UShort")
NumPut(0xFFFFFFFF, toaddr, 4, "UInt")
VarSetCapacity(broadcast,16) , broadcast = 1 
DllCall("Ws2_32\setsockopt", "UInt", sendsock, "UInt", 0xFFFF, "UInt", 0x20, "UInt", &broadcast, "Int", 16)

DllCall("Ws2_32\WSAAsyncSelect", "UInt", recvsock, "UInt", WinExist("A"), "UInt", 0x5555, "Int", 0x1)
OnMessage(0x5555, "WinsockMessage")

if ( log := DllCall("Ws2_32\WSAGetLastError") ) {
msgbox WinSock error %log%
exitapp
}
else {
log := "Tiny UDP ready ! " a_IPAddress1 ":" Port
Guicontrol,, LogEdit, %log%
DllCall("Ws2_32\sendto", "UInt", sendsock, "Str", "connected", "UInt", 9, "UInt", 0x4, "UInt", &toaddr, "UInt", 32)
}
return

; ----------------------------------------------------------------

WinsockMessage(socket, event)
{
Critical
global log, recvsock

  VarSetCapacity(recvdata, 256, 0)
  VarSetCapacity(fromaddr, 32, 0)
  VarSetCapacity(buff, 64)
  DllCall("Ws2_32\recvfrom", "UInt", recvsock, "Str", recvdata, "UInt", 256, "UInt", 0, "UInt", &fromaddr, "UInt", &buff)
  log .= "`n" NumGet(fromaddr, 4, "UChar")
  loop 3
  log .= "." NumGet(fromaddr, 4+A_Index, "UChar")
  log .= " : " recvdata
; if recvdata = myaction then gosub mylabel

Guicontrol,, LogEdit, %log%
controlsend, edit1, ^{end}, Tiny UDP
} 

; ----------------------------------------------------------------

SendButton:
GuiControlGet, senddata

If ( senddata="connected" || senddata="disconnected" )
return

If ( InStr(senddata, "/")=1 && pos:=InStr(senddata, " ") ) {
log .= "`n" senddata
NumPut(DllCall("Ws2_32\inet_addr", "Str", SubStr(senddata, 2, pos-2)), toaddr, 4, "UInt")
senddata:=SubStr(senddata, pos+1)
Guicontrol,, LogEdit, %log%
controlsend, edit1, ^{end}, Tiny UDP
}
Else
NumPut(0xFFFFFFFF, toaddr, 4, "UInt")

DllCall("Ws2_32\sendto", "UInt", sendsock, "Str", senddata, "UInt", StrLen(senddata), "UInt", 0x4, "UInt", &toaddr, "UInt", 32)

Guicontrol,, senddata,
return

; ----------------------------------------------------------------

#IfWinActive , Tiny UDP
up::
guicontrol,, senddata, %senddata%
return

down::
sendinput, /%a_IPAddress1%
return

enter::
gosub SendButton
return

; ----------------------------------------------------------------

GuiClose:
ExitSub:
NumPut(0xFFFFFFFF, toaddr, 4, "UInt")
DllCall("Ws2_32\sendto", "UInt", sendsock, "Str", "disconnected", "UInt", 12, "UInt", 0x4, "UInt", &toaddr, "UInt", 32)
DllCall("Ws2_32\WSACleanup")
ExitApp

However, I can't have web address... I have address of my router (X.X.X.254), anybody know how configure router or to have the real address ? ( peername on unconnected socket) or to have the header of source address in layer of UDP ( or it change with router ? )

krisj209
  • Members
  • 10 posts
  • Last active: Feb 13 2012 09:01 AM
  • Joined: 16 Nov 2007
I think this is what you are trying to do... disregard if it is not.

Login to your router. Find the port forwarding section. Add an entry for the port you want to listen to and enter the private ip address of the computer that you want to be listening.

You can find your public (web address) by going to <!-- w -->www.whatismyip.com<!-- w -->.

Better yet, you might also want to check out dyndns.com 's free service that allows you to setup an alias that will point to your public ip address and will update if it changes (dynamic ip address). For instance you can have something like zaelia.dyndns.com point to your public ip address.

I think you may need to adapt your script a little to make this work, but it should be fairly easy for you.. there are 2 ways that I know you could do it.. 1) allow the alias domain name to be used instead of an ip address.
2) use ping to translate the alias to the ip address.

Keep up the good work!
Men occasionally stumble over the truth, but most of them pick themselves up and hurry off as if nothing ever happened.

-Sir Winston Churchill

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

I think this is what you are trying to do... disregard if it is not.


It's my fault, my question is not well established, clearly specified.
In fact, I already open a port with my router and redirect to my computer, and I can use a dynamic ip address with an URL also... it's works, it's not a problem... But if I receiv an incoming connection from outside my local network the adress info retreive me the address of my router not the true web address, it's like the header of UDP or IP changing with router redirection :(

Of course I can include the web address in the data message, but it's not cool... that's why I wonder why if they are an option with my router for fix this, OR with setsockopt() for don't change header during redirection.

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
about ipv6 ( for keep a trace )

<!-- m -->http://www.autohotke... ... 223#359223<!-- m -->
<!-- m -->http://www.autohotke...pic.php?t=58695<!-- m -->

wnltl
  • Members
  • 8 posts
  • Last active: May 09 2013 01:20 PM
  • Joined: 12 Jun 2012
This script has been very helpful. Thank you very much.