Popular Post j0kky Posted April 1, 2016 Popular Post Share Posted April 1, 2016 (edited) Hi guys, some time ago I tried to deal with client\server application using native winsock functions, but I encountered some difficult because their limitations, so I decided to write a new UDF based on winsock library. Some functions are simply wrappers of native function, but some other are completely renewed and there are a lot of improvements. Check it out! Each function has a detailed description and I attached 5 simple example script expandcollapse popup; #INDEX# ======================================================================================================================= ; Title .........: Winsock ; AutoIt Version : 3.3.14.2 ; Language ......: English ; Description ...: Functions that assist with Winsock library management. ; Author(s) .....: j0kky ; =============================================================================================================================== ; #CONSTANTS# =================================================================================================================== Global Const $TCP_DATA_EOT = 2 ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _TCPStartup ; _TCPListen ; _TCPAccept ; _TCPRecv ; _TCPConnect ; _TCPSend ; _TCPNameToIP ; _TCPCloseSocket ; _TCPShutdown ; _GetIps ; _UDPStartup ; _UDPBind ; _UDPSendTo ; _UDPRecvFrom ; _UDPCloseSocket ; _UDPShutdown ; =============================================================================================================================== ; #WRAPPER# ===================================================================================================================== Func _TCPStartup() $iResult = TCPStartup() Return SetError(@error, 0, $iResult) EndFunc ;==>_TCPStartup ; #WRAPPER# ===================================================================================================================== Func _TCPListen($iIPAddr, $iPort, $iMaxPendingConnection = 0) If Not $iMaxPendingConnection Then $iResult = TCPListen($iIPAddr, $iPort) Else $iResult = TCPListen($iIPAddr, $iPort, $iMaxPendingConnection) EndIf Return SetError(@error, 0, $iResult) EndFunc ;==>_TCPListen ; #FUNCTION# ==================================================================================================================== ; Name...........: _TCPAccept ; Description ...: Permits an incoming connection attempt on a socket. ; Syntax.........: _TCPAccept($iMainsocket) ; Parameters ....: $iMainsocket - The main socket identifier (SocketID) as returned by _TCPListen function. ; Return values .: On success it returns an array: ; |[0] - The connected socket identifier. ; |[1] - The external address of the client ; |[2] - The external port which the client are communicating on ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter (not used in this function) ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: j0kky ; Modified ......: 1.0.0 ; Links .........: accept: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _TCPAccept($iMainsocket) $iMainsocket = Number($iMainsocket) If $iMainsocket < 0 Then Return SetError(-4, 0, -1) ; invalid parameter Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0, $hSock = 0 Local $tagSockAddr = "short sin_family; ushort sin_port; " & _ "STRUCT; ulong S_addr; ENDSTRUCT; " & _ ;sin_addr "char sin_zero[8]" If Not $bError Then $aRet = DllCall($hWs2, "int", "ioctlsocket", "uint", $iMainsocket, "long", 0x8004667e, "ulong*", 1) ;FIONBIO If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf EndIf If Not $bError Then $tSockAddr = DllStructCreate($tagSockAddr) $aRet = DllCall($hWs2, "uint", "accept", "uint", $iMainsocket, "ptr", DllStructGetPtr($tSockAddr), "int*", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf ($aRet[0] = 4294967295) Or ($aRet[0] = -1) Then ;INVALID_SOCKET $bError = 1 $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $bError = -1 ElseIf ($aRet[0] = 0) Or ($aRet[0] = 10035) Then ;WSAEWOULDBLOCK $nCode = -10 ;internal function value, it means no error EndIf Else $hSock = $aRet[0] $aRet = DllCall($hWs2, "ptr", "inet_ntoa", "ulong", DllStructGetData($tSockAddr, "S_addr")) If @error Then $bError = -1 ElseIf $aRet[0] = Null Then $bError = 1 Else $sIPAddr = DllStructGetData(DllStructCreate("char[15]", $aRet[0]), 1) $aRet = DllCall($hWs2, "ushort", "ntohs", "ushort", DllStructGetData($tSockAddr, "sin_port")) If @error Then $bError = -1 Else $nPort = $aRet[0] Local $aResult[3] = [$hSock, $sIPAddr, $nPort] EndIf EndIf EndIf EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure If $hSock Then TCPCloseSocket($hSock) ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf If $nCode = -10 Then $nCode = 0 $nReturn = -1 If $hSock Then TCPCloseSocket($hSock) Else $nReturn = $aResult EndIf DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_TCPAccept ; #FUNCTION# ==================================================================================================================== ; Name...........: _TCPRecv ; Description ...: Receives data from a connected socket. ; Syntax.........: _TCPRecv($iMainsocket, $iMaxLen, $iFlag = 0) ; Parameters ....: $iMainsocket - The array as returned by _TCPAccept ; or the connected socket identifier (SocketID) as returned by _TCPConnect. ; $iMaxLen - max # of characters to receive (usually 2048). ; $iFlag - values can be added together ; |$TCP_DATA_DEFAULT (0) - Text data. [Default] ; |$TCP_DATA_BINARY (1) - Binary data. ; |$TCP_DATA_EOT (2) - Returns data received and ; set @error to -6 when it reaches the End of Text ASCII character (Chr(3)) ; Return values .: On success it returns the binary/string sent by the connected socket. ; On failure it returns "" and sets the @error or @extended flag to non-zero: ; @error values: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; @extended values: ; |1 - connection closed ; |2 - End of Text reached ; Author ........: j0kky ; Modified ......: 1.0.0 ; Remarks .......: If Unicode strings need to be transmitted they must be encoded/decoded with StringToBinary()/BinaryToString(). ; $iFlag = 2 must be set in couple with _TCPSend ; You must check for both @error and @extended, @extended could be set with @error set to zero ; Links .........: recv: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _TCPRecv($iMainsocket, $iMaxLen, $iFlag = 0) If IsArray($iMainsocket) And (UBound($iMainsocket, 0) = 1) And (UBound($iMainsocket) > 0) Then $iMainsocket = $iMainsocket[0] If $iFlag = Default Then $iFlag = 0 $iMainsocket = Number($iMainsocket) $iMaxLen = Number($iMaxLen) $iFlag = Number($iFlag) If $iMainsocket < 0 Or _ $iMaxLen < 1 Or _ Not ($iFlag = 0 Or $iFlag = 1 Or $iFlag = 2) Then Return SetError(-4, 0, -1) ; invalid parameter Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0, $nExtended = 0 If Not $bError Then $aRet = DllCall($hWs2, "int", "ioctlsocket", "uint", $iMainsocket, "long", 0x8004667e, "ulong*", 1) ;FIONBIO If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf EndIf Local $tBuf If $iFlag Then $tBuf = DllStructCreate("byte[" & $iMaxLen & "]") Else $tBuf = DllStructCreate("char[" & $iMaxLen & "]") EndIf $aRet = DllCall($hWs2, "int", "recv", "uint", $iMainsocket, "ptr", DllStructGetPtr($tBuf), "int", $iMaxLen, "int", 0) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Then ;SOCKET_ERROR $bError = 1 $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $bError = -1 ElseIf $aRet[0] = 0 Or $aRet[0] = 10035 Then ;WSAEWOULDBLOCK $nCode = -10 ;internal function value, it means no error EndIf ElseIf $aRet[0] = 0 Then $bError = 1 $nCode = -10 $nExtended = 1 ;connection closed Else Local $sResult = DllStructGetData($tBuf, 1) ;data If BitAND($iFlag, 2) = 2 Then ;EOT If StringRight($sResult, 1) = Chr(3) Then $sResult = StringTrimRight($sResult, 1) $nExtended = 2 ;End of Text reached EndIf EndIf EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = "" ;failure ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf If $nCode = -10 Then $nCode = 0 $nReturn = "" Else $nReturn = $sResult EndIf DllClose($hWs2) Return SetError($nCode, $nExtended, $nReturn) EndFunc ;==>_TCPRecv ; #FUNCTION# ==================================================================================================================== ; Name...........: _TCPConnect ; Description ...: Create a socket connected to an existing server. ; Syntax.........: _TCPConnect($sIPAddr, $iDestPort, $sSourceAddr = "", $iSourcePort = 0, $iTimeOut = 0) ; Parameters ....: $sIPAddr - Destination IP. ; |Internet Protocol dotted address(IpV4) as "192.162.1.1". ; $iDestPort - Destination port. ; |1 : 65534 - port on which the created socket will be connected. ; $sSourceAddr - Source IP ; |Internet Protocol dotted address(IpV4) as "192.162.1.1". [Default = ""] ; $iSourcePort - Source port. ; |1 : 65534 - port on which the created socket will be bind (on the local PC). [Default = 0] ; $iTimeOut - The maximum time in milliseconds for _TCPConnect to wait for connection. ; |Any value > 0 [Default = 0 and it will be equal to Opt("TCPTimeout")]. ; Return values .: On success it returns the main socket identifier. ; |Any value > 0 ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter ; |-5 - not connected ; |-6 - timed out ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: j0kky ; Modified ......: 1.0.0 ; Remarks .......: This function is used by a client to communicate with the server and it allows to choose a source IP, ; a source port and to set a timeout for the connection. ; Links .........: bind: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737550(v=vs.85).aspx ; connect: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx ; select: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _TCPConnect($sIPAddr, $iDestPort, $sSourceAddr = "", $iSourcePort = 0, $iTimeOut = 0) If $sSourceAddr = Default Then $sSourceAddr = "" If $iSourcePort = Default Then $iSourcePort = 0 If $iTimeOut = Default Then $iTimeOut = 0 $sIPAddr = String($sIPAddr) $iDestPort = Number($iDestPort) $sSourceAddr = String($sSourceAddr) $iSourcePort = Number($iSourcePort) $iTimeOut = Number($iTimeOut) If Not ($iDestPort > 0 And $iDestPort < 65535) Or _ Not ($iSourcePort >= 0 And $iSourcePort < 65535) Or _ Not ($iTimeOut >= 0) Then Return SetError(-4, 0, -1) ; invalid parameter StringRegExp($sIPAddr, "((?:\d{1,3}\.){3}\d{1,3})", 3) ;$STR_REGEXPARRAYGLOBALMATCH If @error Then Return SetError(-4, 0, -1) If $sSourceAddr <> "" Then StringRegExp($sSourceAddr, "((?:\d{1,3}\.){3}\d{1,3})", 3) ;$STR_REGEXPARRAYGLOBALMATCH If @error Then Return SetError(-4, 0, -1) EndIf Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0 Local $tagSockAddr = "short sin_family; ushort sin_port; " & _ "STRUCT; ulong S_addr; ENDSTRUCT; " & _ ;sin_addr "char sin_zero[8]" Local $hSock = DllCall($hWs2, "uint", "socket", "int", 2, "int", 1, "int", 6); AF_INET, SOCK_STREAM, IPPROTO_TCP If @error Then $bError = -1 ElseIf ($hSock[0] = 4294967295) Or ($hSock[0] = -1) Then ;INVALID_SOCKET $bError = 1 Else $hSock = $hSock[0] EndIf If Not $bError Then $aRet = DllCall($hWs2, "ulong", "inet_addr", "str", $sIPAddr) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Or ($aRet[0] = 0) Then ;INADDR_NONE or INADDR_ANY $bError = 1 Else $sIPAddr = $aRet[0] EndIf EndIf If Not $bError Then $aRet = DllCall($hWs2, "ushort", "htons", "ushort", $iDestPort) If @error Then $bError = -1 Else $iDestPort = $aRet[0] EndIf EndIf If (Not $bError) And ($sSourceAddr <> "") Then $aRet = DllCall($hWs2, "ulong", "inet_addr", "str", $sSourceAddr) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Or ($aRet[0] = 0) Then ;INADDR_NONE or INADDR_ANY $bError = 1 Else $sSourceAddr = $aRet[0] EndIf EndIf If (Not $bError) And $iSourcePort Then $aRet = DllCall($hWs2, "ushort", "htons", "ushort", $iSourcePort) If @error Then $bError = -1 Else $iSourcePort = $aRet[0] EndIf EndIf If (Not $bError) And ($sSourceAddr Or $iSourcePort) Then $tSockAddr = DllStructCreate($tagSockAddr) DllStructSetData($tSockAddr, "sin_family", 2) ;AF_INET If $iSourcePort Then DllStructSetData($tSockAddr, "sin_port", $iSourcePort) Else DllStructSetData($tSockAddr, "sin_port", 0) EndIf If $sSourceAddr Then DllStructSetData($tSockAddr, "S_addr", $sSourceAddr) Else DllStructSetData($tSockAddr, "S_addr", 0x00000000) ;INADDR_ANY EndIf $aRet = DllCall($hWs2, "int", "bind", "uint", $hSock, "ptr", DllStructGetPtr($tSockAddr), "int", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf $tSockAddr = 0 EndIf If Not $bError Then $aRet = DllCall($hWs2, "int", "ioctlsocket", "uint", $hSock, "long", 0x8004667e, "ulong*", 1) ;FIONBIO If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf EndIf If Not $bError Then $tSockAddr = DllStructCreate($tagSockAddr) DllStructSetData($tSockAddr, "sin_family", 2) ;AF_INET DllStructSetData($tSockAddr, "sin_port", $iDestPort) DllStructSetData($tSockAddr, "S_addr", $sIPAddr) $aRet = DllCall($hWs2, "int", "connect", "uint", $hSock, "ptr", DllStructGetPtr($tSockAddr), "int", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR -> functional with connect() on non-blocking sockets $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $bError = -1 ElseIf ($aRet[0] <> 0) And ($aRet[0] <> 10035) Then ;WSAEWOULDBLOCK $bError = 1 EndIf EndIf $tSockAddr = 0 EndIf If Not $bError Then If $iTimeOut = 0 Then $iTimeOut = Opt("TCPTimeout") If $iTimeOut < 1 Then $iTimeOut = 100 Local $tagFd_set = "uint fd_count; uint fd_array[64]" Local $tFd_set_writefds = DllStructCreate($tagFd_set) DllStructSetData($tFd_set_writefds, "fd_count", 1) DllStructSetData($tFd_set_writefds, "fd_array", $hSock, 1) Local $tFd_set_exceptfds = DllStructCreate($tagFd_set) DllStructSetData($tFd_set_exceptfds, "fd_count", 1) DllStructSetData($tFd_set_exceptfds, "fd_array", $hSock, 1) Local $tTimeval = DllStructCreate("long tv_sec; long tv_usec") DllStructSetData($tTimeval, "tv_sec", Floor($iTimeOut / 1000)) DllStructSetData($tTimeval, "tv_usec", Round(Mod($iTimeOut, 1000) * 1000)) $aRet = DllCall($hWs2, "int", "select", _ "int", $hSock, "ptr", 0, "ptr", DllStructGetPtr($tFd_set_writefds), "ptr", DllStructGetPtr($tFd_set_exceptfds), "ptr", DllStructGetPtr($tTimeval)) If @error Then $bError = -1 ElseIf $aRet[0] = 0 Then ;time expired $bError = 1 $nCode = -6 ;timed out, similar to WSAETIMEDOUT ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Then ;SOCKET_ERROR $bError = 1 Else If Not (DllStructGetData($tFd_set_writefds, "fd_count") = 1) Then $bError = 1 If DllStructGetData($tFd_set_exceptfds, "fd_count") = 1 Then $tBuf = DllStructCreate("int") $aRet = DllCall("Ws2_32.dll", "int", "getsockopt", _ "uint", $hSock, "int", 0xffff, "int", 0x1007, "ptr", DllStructGetPtr($tBuf), "int*", DllStructGetSize($tBuf)) ;SO_ERROR If @error Then $bError = -1 ElseIf $aRet[0] = 0 Then $nCode = DllStructGetData($tBuf, 1) EndIf Else $nCode = -5 ;NOT_CONNECTED EndIf EndIf EndIf EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure If $hSock Then TCPCloseSocket($hSock) ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf $nReturn = -1 If $hSock Then TCPCloseSocket($hSock) Else $nReturn = $hSock EndIf DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_TCPConnect ; #MODIFIED WRAPPER# ============================================================================================================ ; Name...........: _TCPSend ; Description ...: Wrapper of _TCPSend function, see the guide. ; Syntax.........: _TCPSend($iMainsocket, $iData, $iFlag = 0) ; Parameters ....: $iMainsocket - The array as returned by _TCPAccept ; or the connected socket identifier (SocketID) as returned by _TCPConnect. ; $iData - Data sent. ; |Text or binary data ; $iFlag - values can be added together ; |$TCP_DATA_DEFAULT (0) - It doesn't add anything at the end of the string [Default] ; |$TCP_DATA_EOT (2) - It adds an End of Text ASCII character (Chr(3)) at the end of the string ; Return values .: see the guide. ; Author ........: j0kky ; Modified ......: 1.0.0 ; Remarks .......: If Unicode strings need to be transmitted they must be encoded/decoded with StringToBinary()/BinaryToString(). ; $iFlag = $TCP_DATA_EOT must be set in couple with _TCPRecv, so don't use it for external application ; Links .........: send: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740149(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _TCPSend($iMainsocket, $iData, $iFlag = 0) If IsArray($iMainsocket) And (UBound($iMainsocket, 0) = 1) And (UBound($iMainsocket) > 0) Then $iMainsocket = $iMainsocket[0] If BitAND($iFlag, 2) = 2 Then $iData = String($iData) & Chr(3) $iResult = TCPSend($iMainsocket, $iData) Return SetError(@error, 0, $iResult) EndFunc ;==>_TCPSend ; #WRAPPER# ===================================================================================================================== Func _TCPNameToIP($sName) $iResult = TCPNameToIP($sName) Return SetError(@error, 0, $iResult) EndFunc ;==>_TCPNameToIP ; #FUNCTION# ==================================================================================================================== ; Name...........: _GetIps ; Description ...: Get local and public IP address of a network/computer ; Syntax.........: _GetIps($iServerName = "") ; Parameters ....: $iServerName - The server name which can retrieve your public IP ; |For example: "www.something.com/somethingelse" [Default = ""] ; Return values .: On success it returns an array: ; |[0] - Local IP (on LAN) of the adapter used to connect to Internet. ; |[1] - Public IP. ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter (not used) ; |-5 - servers are offline ; |-6 - IP retrieving failed ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: j0kky ; Modified ......: 1.0.0 ; Remarks .......: It works with Winsock library, so it must be initialized with _TCPStartup(). ; Local and public IPs are both retrieved through internet. ; Links .........: error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _GetIps($iServerName = "") If $iServerName = Default Then $iServerName = "" $iServerName = String($iServerName) $iServerName = StringRegExpReplace($iServerName, "^http.?://", "") If StringInStr($iServerName, "/") Then If StringRegExp($iServerName, "/(.*)", 1)[0] Then If StringRight($iServerName, 1) = "/" Then $iServerName = StringTrimRight($iServerName, 1) EndIf Else $iServerName &= "/" EndIf If Not StringRegExp($iServerName, ".+\..{2,}") Then $iServerName = "" ; invalid parameter Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0, $sLocalIP = "", $sPublicIP = "" Local $tagSockAddr = "short sin_family; ushort sin_port; " & _ "STRUCT; ulong S_addr; ENDSTRUCT; " & _ ;sin_addr "char sin_zero[8]" Local $hSock = DllCall($hWs2, "uint", "socket", "int", 2, "int", 1, "int", 6); AF_INET, SOCK_STREAM, IPPROTO_TCP If @error Then $bError = -1 ElseIf ($hSock[0] = 4294967295) Or ($hSock[0] = -1) Then ;INVALID_SOCKET $bError = 1 Else $hSock = $hSock[0] EndIf If Not $bError Then If $iServerName Then Local $aGetIPURL[][2] = [["www.myexternalip.com/raw"], ["checkip.dyndns.org/"], ["bot.whatismyipaddress.com/"], [$iServerName]], $nElements = 0 Else Local $aGetIPURL[][2] = [["www.myexternalip.com/raw"], ["checkip.dyndns.org/"], ["bot.whatismyipaddress.com/"]], $nElements = 0 EndIf For $i = 0 To (UBound($aGetIPURL) - 1) $sServerIp = TCPNameToIP(StringRegExp($aGetIPURL[$i][0], "(.*?)/", 1)[0]) If $sServerIp <> "" Then $aGetIPURL[$nElements][0] = $aGetIPURL[$i][0] $aGetIPURL[$nElements][1] = $sServerIp $nElements += 1 EndIf Next If $nElements Then ReDim $aGetIPURL[$nElements][2] Else $bError = 1 $nCode = -5 ;there is no valid server for checking IP EndIf EndIf If Not $bError Then $aRet = DllCall($hWs2, "ushort", "htons", "ushort", 80) If @error Then $bError = -1 Else $iDestPort = $aRet[0] EndIf EndIf If Not $bError Then For $i = 0 To (UBound($aGetIPURL) - 1) $sServerIp = $aGetIPURL[$i][1] If Not $bError Then $aRet = DllCall($hWs2, "int", "ioctlsocket", "uint", $hSock, "long", 0x8004667e, "ulong*", 1) ;FIONBIO If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf EndIf If Not $bError Then $aRet = DllCall($hWs2, "ulong", "inet_addr", "str", $sServerIp) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Or ($aRet[0] = 0) Then ;INADDR_NONE or INADDR_ANY $bError = 1 Else $sServerIp = $aRet[0] EndIf EndIf If Not $bError Then $tSockAddr = DllStructCreate($tagSockAddr) DllStructSetData($tSockAddr, "sin_family", 2) ;AF_INET DllStructSetData($tSockAddr, "sin_port", $iDestPort) DllStructSetData($tSockAddr, "S_addr", $sServerIp) $aRet = DllCall($hWs2, "int", "connect", "uint", $hSock, "ptr", DllStructGetPtr($tSockAddr), "int", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR -> functional with connect() on non-blocking sockets $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $bError = -1 ElseIf ($aRet[0] <> 0) And ($aRet[0] <> 10035) Then ;WSAEWOULDBLOCK $bError = 1 EndIf EndIf $tSockAddr = 0 EndIf If Not $bError Then Local $tagFd_set = "uint fd_count; uint fd_array[64]" Local $tFd_set_writefds = DllStructCreate($tagFd_set) DllStructSetData($tFd_set_writefds, "fd_count", 1) DllStructSetData($tFd_set_writefds, "fd_array", $hSock, 1) Local $tFd_set_exceptfds = DllStructCreate($tagFd_set) DllStructSetData($tFd_set_exceptfds, "fd_count", 1) DllStructSetData($tFd_set_exceptfds, "fd_array", $hSock, 1) Local $tTimeval = DllStructCreate("long tv_sec; long tv_usec") DllStructSetData($tTimeval, "tv_sec", Floor(500 / 1000)) DllStructSetData($tTimeval, "tv_usec", Round(Mod(500, 1000) * 1000)) $aRet = DllCall($hWs2, "int", "select", _ "int", $hSock, "ptr", 0, "ptr", DllStructGetPtr($tFd_set_writefds), "ptr", DllStructGetPtr($tFd_set_exceptfds), "ptr", DllStructGetPtr($tTimeval)) If @error Then $bError = -1 ElseIf ($aRet[0] = 0) Or ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Then $bError = 1 Else If Not (DllStructGetData($tFd_set_writefds, "fd_count") = 1) Then $bError = 1 EndIf EndIf If Not $bError And Not $sLocalIP Then $tSockAddr = DllStructCreate($tagSockAddr) $aRet = DllCall($hWs2, "int", "getsockname", "uint", $hSock, "ptr", DllStructGetPtr($tSockAddr), "int*", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 Else $aRet = DllCall($hWs2, "ptr", "inet_ntoa", "ulong", DllStructGetData($tSockAddr, "S_addr")) If @error Then $bError = -1 ElseIf $aRet[0] = Null Then $bError = 1 Else $sLocalIP = DllStructGetData(DllStructCreate("char[15]", $aRet[0]), 1) ;IP address EndIf EndIf $tSockAddr = 0 EndIf If Not $bError Then $sRequest = "GET /" & StringRegExp($aGetIPURL[$i][0], "/(.*)", 1)[0] & " HTTP/1.1" & @CRLF & _ "Host: " & StringRegExp($aGetIPURL[$i][0], "(.*?)/", 1)[0] & @CRLF & _ "Connection: close" & @CRLF & @CRLF TCPSend($hSock, $sRequest) Local $sRecv = "", $hTimer = TimerInit() While 1 $sRecv &= _TCPRecv($hSock, 2048) If @error Or @extended Then If @error Then $bError = 1 ExitLoop EndIf If TimerDiff($hTimer) > 2500 Then ExitLoop Sleep(10) WEnd EndIf If Not $bError Then $aPublicIP = StringRegExp($sRecv, "((?:\d{1,3}\.){3}\d{1,3})", 3) ;STR_REGEXPARRAYGLOBALMATCH If Not @error Then $sPublicIP = $aPublicIP[0] ExitLoop Else $bError = 1 EndIf EndIf If $bError And $i = (UBound($aGetIPURL) - 1) Then $nCode = -6 ExitLoop Else $bError = 0 $nCode = 0 TCPCloseSocket($hSock) EndIf Local $hSock = DllCall($hWs2, "uint", "socket", "int", 2, "int", 1, "int", 6); AF_INET, SOCK_STREAM, IPPROTO_TCP If @error Then $bError = -1 ElseIf ($hSock[0] = 4294967295) Or ($hSock[0] = -1) Then ;INVALID_SOCKET $bError = 1 Else $hSock = $hSock[0] EndIf Next EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf $nReturn = -1 Else Local $nReturn[2] = [$sLocalIP, $sPublicIP] EndIf If $hSock Then TCPCloseSocket($hSock) DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_GetIps ; #MODIFIED WRAPPER# ============================================================================================================ ; Name...........: _TCPCloseSocket ; Description ...: Wrapper of TCPCloseSocket function, see the guide. ; Syntax.........: _TCPCloseSocket($iMainsocket) ; Parameters ....: $iMainsocket - The array as returned by _TCPAccept ; or the connected socket identifier (SocketID) as returned by _TCPListen and _TCPConnect. ; Return values .: see the guide. ; Author ........: j0kky ; Modified ......: 1.0.0 ; Links .........: recv: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _TCPCloseSocket($iMainsocket) If IsArray($iMainsocket) And (UBound($iMainsocket, 0) = 1) And (UBound($iMainsocket) > 0) Then $iMainsocket = $iMainsocket[0] $iResult = TCPCloseSocket($iMainsocket) Return SetError(@error, 0, $iResult) EndFunc ;==>_TCPCloseSocket ; #WRAPPER# ===================================================================================================================== Func _TCPShutdown() $iResult = TCPShutdown() Return SetError(@error, 0, $iResult) EndFunc ;==>_TCPShutdown ; #WRAPPER# ===================================================================================================================== Func _UDPStartup() $iResult = UDPStartup() Return SetError(@error, 0, $iResult) EndFunc ;==>_UDPStartup ; #FUNCTION# ==================================================================================================================== ; Name...........: _UDPBind ; Description ...: Creates and bind a socket to a local IP and a local port. ; Syntax.........: _UDPBind($sSourceAddr = "", $iSourcePort = 0) ; Parameters ....: $sSourceAddr - Source IP ; |Internet Protocol dotted address(IpV4) as "192.162.1.1". [Default = ""] ; $iSourcePort - Source port. ; |1 : 65534 - port on which the created socket will be bind (on the local PC). [Default = 0] ; Return values .: On success it returns the main socket identifier. ; |Any value > 0 ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: j0kky ; Modified ......: 1.0.0 ; Remarks .......: It could be used before both of _UDPSendTo (client app) and _UDPRecvFrom (server app) functions ; Links .........: bind: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737550(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _UDPBind($sSourceAddr = "", $iSourcePort = 0) If $sSourceAddr = Default Then $sSourceAddr = "" If $iSourcePort = Default Then $iSourcePort = 0 $sSourceAddr = String($sSourceAddr) $iSourcePort = Number($iSourcePort) If Not ($iSourcePort >= 0 And $iSourcePort < 65535) Then Return SetError(-4, 0, -1) ; invalid parameter If $sSourceAddr <> "" Then StringRegExp($sSourceAddr, "((?:\d{1,3}\.){3}\d{1,3})", 3) ;$STR_REGEXPARRAYGLOBALMATCH If @error Then Return SetError(-4, 0, -1) EndIf Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0 Local $tagSockAddr = "short sin_family; ushort sin_port; " & _ "STRUCT; ulong S_addr; ENDSTRUCT; " & _ ;sin_addr "char sin_zero[8]" Local $hSock = DllCall($hWs2, "uint", "socket", "int", 2, "int", 2, "int", 17); AF_INET, SOCK_DGRAM, IPPROTO_UDP If @error Then $bError = -1 ElseIf ($hSock[0] = 4294967295) Or ($hSock[0] = -1) Then ;INVALID_SOCKET $bError = 1 Else $hSock = $hSock[0] EndIf If (Not $bError) And ($sSourceAddr <> "") Then $aRet = DllCall($hWs2, "ulong", "inet_addr", "str", $sSourceAddr) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Or ($aRet[0] = 0) Then ;INADDR_NONE or INADDR_ANY $bError = 1 Else $sSourceAddr = $aRet[0] EndIf EndIf If (Not $bError) And $iSourcePort Then $aRet = DllCall($hWs2, "ushort", "htons", "ushort", $iSourcePort) If @error Then $bError = -1 Else $iSourcePort = $aRet[0] EndIf EndIf If Not $bError Then $tSockAddr = DllStructCreate($tagSockAddr) DllStructSetData($tSockAddr, "sin_family", 2) ;AF_INET If $iSourcePort Then DllStructSetData($tSockAddr, "sin_port", $iSourcePort) Else DllStructSetData($tSockAddr, "sin_port", 0) EndIf If $sSourceAddr Then DllStructSetData($tSockAddr, "S_addr", $sSourceAddr) Else DllStructSetData($tSockAddr, "S_addr", 0x00000000) ;INADDR_ANY EndIf $aRet = DllCall($hWs2, "int", "bind", "uint", $hSock, "ptr", DllStructGetPtr($tSockAddr), "int", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf $tSockAddr = 0 EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure If $hSock Then UDPCloseSocket($hSock) ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf $nReturn = -1 If $hSock Then UDPCloseSocket($hSock) Else $nReturn = $hSock EndIf DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_UDPBind ; #FUNCTION# ==================================================================================================================== ; Name...........: _UDPSendTo ; Description ...: Sends data to an address/port, it uses a socket created by _UDPBind or it creates a socket itself ; Syntax.........: _UDPSendTo($sIPAddr, $iDestPort, $iData, $iMainsocket = 0) ; Parameters ....: $sIPAddr - Destination IP. ; |Internet Protocol dotted address(IpV4) as "192.162.1.1". ; $iDestPort - Destination port. ; |1 : 65534 - port which the created socket will connect on. ; $iData - Data sent. ; |Text or binary data ; $iMainsocket - Main socket identifier returned by _UDPBind. ; |Any value > 0 [Default = 0] ; Return values .: On success it returns an array: ; |[0] - The number of bytes sent. ; |[1] - The main socket identifier used. ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: j0kky ; Modified ......: 1.0.0 ; Links .........: sendto: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740148(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _UDPSendTo($sIPAddr, $iDestPort, $iData, $iMainsocket = 0) If $iMainsocket = Default Then $iMainsocket = 0 $iMainsocket = Number($iMainsocket) $sIPAddr = String($sIPAddr) $iDestPort = Number($iDestPort) If Not IsBinary($iData) Then $iData = String($iData) If Not ($iDestPort > 0 And $iDestPort < 65535) Or _ $iMainsocket < 0 Then Return SetError(-4, 0, -1) ; invalid parameter StringRegExp($sIPAddr, "((?:\d{1,3}\.){3}\d{1,3})", 3) ;$STR_REGEXPARRAYGLOBALMATCH If @error Then Return SetError(-4, 0, -1) Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0 Local $tagSockAddr = "short sin_family; ushort sin_port; " & _ "STRUCT; ulong S_addr; ENDSTRUCT; " & _ ;sin_addr "char sin_zero[8]" If Not $iMainsocket Then Local $aRet = DllCall($hWs2, "uint", "socket", "int", 2, "int", 2, "int", 17); AF_INET, SOCK_DGRAM, IPPROTO_UDP If @error Then $bError = -1 ElseIf ($aRet[0] = 4294967295) Or ($aRet[0] = -1) Then ;INVALID_SOCKET $bError = 1 Else $iMainsocket = $aRet[0] EndIf EndIf If Not $bError Then $aRet = DllCall($hWs2, "ulong", "inet_addr", "str", $sIPAddr) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Or ($aRet[0] = 0) Then ;INADDR_NONE or INADDR_ANY $bError = 1 Else $sIPAddr = $aRet[0] EndIf EndIf If Not $bError Then $aRet = DllCall($hWs2, "ushort", "htons", "ushort", $iDestPort) If @error Then $bError = -1 Else $iDestPort = $aRet[0] EndIf EndIf If Not $bError Then $aRet = DllCall($hWs2, "int", "ioctlsocket", "uint", $iMainsocket, "long", 0x8004667e, "ulong*", 1) ;FIONBIO If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf EndIf If Not $bError Then Local $tSockAddr = DllStructCreate($tagSockAddr) DllStructSetData($tSockAddr, "sin_family", 2) ;AF_INET DllStructSetData($tSockAddr, "sin_port", $iDestPort) DllStructSetData($tSockAddr, "S_addr", $sIPAddr) Local $nLenght, $tBuf If IsBinary($iData) Then $nLenght = BinaryLen($iData) $tBuf = DllStructCreate("byte[" & $nLenght & "]") DllStructSetData($tBuf, 1, $iData) Else $nLenght = StringLen($iData) $tBuf = DllStructCreate("char[" & $nLenght & "]") DllStructSetData($tBuf, 1, $iData) EndIf $aRet = DllCall($hWs2, "int", "sendto", _ "uint", $iMainsocket, "ptr", DllStructGetPtr($tBuf), "int", $nLenght, "int", 0, "ptr", DllStructGetPtr($tSockAddr), "int", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Then ;SOCKET_ERROR $bError = 1 Else Local $aReturn[2] = [$aRet[0], $iMainsocket] EndIf EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf $nReturn = -1 Else $nReturn = $aReturn EndIf DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_UDPSendTo ; #FUNCTION# ==================================================================================================================== ; Name...........: _UDPRecvFrom ; Description ...: Receives data from a bound socket on the local PC. ; Syntax.........: _UDPRecvFrom($iMainsocket, $iMaxLen, $iFlag = 0) ; Parameters ....: $iMainsocket - Main socket identifier. ; |Any value > 0 ; $iMaxLen - Max # of characters to receive (usually 2048). ; $iFlag ; |0 - Text data. [Default] ; |1 - Binary data. ; Return values .: On success it returns an array: ; |[0] - The data received. ; |[1] - The IP address of the sender. ; |[2] - The port used by the sender for connection. ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: j0kky ; Modified ......: 1.0.0 ; Links .........: recvfrom: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740120(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _UDPRecvFrom($iMainsocket, $iMaxLen, $iFlag = 0) If $iFlag = Default Then $iFlag = 0 $iMainsocket = Number($iMainsocket) $iMaxLen = Number($iMaxLen) $iFlag = Number($iFlag) If $iMainsocket < 0 Or _ $iMaxLen < 1 Or _ Not ($iFlag = 0 Or $iFlag = 1) Then Return SetError(-4, 0, -1) ; invalid parameter Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0 Local $tagSockAddr = "short sin_family; ushort sin_port; " & _ "STRUCT; ulong S_addr; ENDSTRUCT; " & _ ;sin_addr "char sin_zero[8]" If Not $bError Then $aRet = DllCall($hWs2, "int", "ioctlsocket", "uint", $iMainsocket, "long", 0x8004667e, "ulong*", 1) ;FIONBIO If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf EndIf Local $tSockAddr = DllStructCreate($tagSockAddr) Local $tBuf If $iFlag Then $tBuf = DllStructCreate("byte[" & $iMaxLen & "]") Else $tBuf = DllStructCreate("char[" & $iMaxLen & "]") EndIf $aRet = DllCall($hWs2, "int", "recvfrom", _ "uint", $iMainsocket, "ptr", DllStructGetPtr($tBuf), "int", $iMaxLen, "int", 0, "ptr", DllStructGetPtr($tSockAddr), "int*", DllStructGetSize($tSockAddr)) If @error Then $bError = -1 ElseIf ($aRet[0] = -1) Or ($aRet[0] = 4294967295) Then ;SOCKET_ERROR $bError = 1 $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $bError = -1 ElseIf $aRet[0] = 0 Or $aRet[0] = 10035 Then ;WSAEWOULDBLOCK $nCode = -10 ;internal function value, it means no error EndIf Else Local $aResult[3] = [DllStructGetData($tBuf, 1)] ;data $aRet = DllCall($hWs2, "ptr", "inet_ntoa", "ulong", DllStructGetData($tSockAddr, "S_addr")) If @error Then $bError = -1 ElseIf $aRet[0] = Null Then $bError = 1 Else $aResult[1] = DllStructGetData(DllStructCreate("char[15]", $aRet[0]), 1) ;IP address $aRet = DllCall($hWs2, "ushort", "ntohs", "ushort", DllStructGetData($tSockAddr, "sin_port")) If @error Then $bError = -1 Else $aResult[2] = $aRet[0] ;port EndIf EndIf EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf If $nCode = -10 Then $nCode = 0 $nReturn = -1 Else $nReturn = $aResult EndIf DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_UDPRecvFrom ; #FUNCTION# ==================================================================================================================== ; Name...........: _UDPCloseSocket ; Description ...: Close a UDP socket. ; Syntax.........: _UDPCloseSocket($iMainsocket) ; Parameters ....: $iMainsocket - Main socket identifier returned by _UDPBind or the array returned by _UDPSendTo. ; |Any value > 0 ; Return values .: On success it returns 1. ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |-4 - invalid parameter ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: j0kky ; Modified ......: 1.0.0 ; Links .........: closesocket: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737582(v=vs.85).aspx ; error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx ; =============================================================================================================================== Func _UDPCloseSocket($iMainsocket) If IsArray($iMainsocket) Then If Not ((UBound($iMainsocket, 0) = 1) And (UBound($iMainsocket) = 2)) Then Return SetError(-1, 0, -4) $iMainsocket = $iMainsocket[1] Else If $iMainsocket < 1 Then Return SetError(-1, 0, -4) EndIf Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0 $aRet = DllCall($hWs2, "int", "closesocket", "uint", $iMainsocket) If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf $nReturn = -1 Else $nReturn = 1 EndIf DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_UDPCloseSocket ; #WRAPPER# ===================================================================================================================== Func _UDPShutdown() $iResult = UDPShutdown() Return SetError(@error, 0, $iResult) EndFunc ;==>_UDPShutdown Obviously there can be a lot of errors, so please report here any problem\suggestion! Updated to: 11/01/16 winsock.zip Edited November 1, 2016 by j0kky Deye, Ascer, TurionAltec and 3 others 6 Spoiler Some UDFs I created: Winsock UDF STUN UDF WinApi_GetAdaptersAddresses _WinApi_GetLogicalProcessorInformation Bitwise with 64 bit integers An useful collection of zipping file UDFs Link to comment Share on other sites More sharing options...
j0kky Posted April 3, 2016 Author Share Posted April 3, 2016 no comment? Spoiler Some UDFs I created: Winsock UDF STUN UDF WinApi_GetAdaptersAddresses _WinApi_GetLogicalProcessorInformation Bitwise with 64 bit integers An useful collection of zipping file UDFs Link to comment Share on other sites More sharing options...
TurionAltec Posted November 27, 2017 Share Posted November 27, 2017 (edited) On the UDF, one feature I like is immediately knowing the IP/port of an incoming client. I've been looking at implementing application level IP filtering. It also looks like TCPRecv will actually respond correctly if the connection is closed. As I recall the built in TCPRecv has been broken in this regard for years. TCP Keepalive I've run into problems where idle connections are dropped from stateful firewalls. Usually after an hour or so, or they drop off a list as being unused (if there's a maximum number of connections). The socket will still appear to be active on both sides, but if the server tries to send data it will fail and close the connection on that side. The client will still think it's connected until it tries to send data. As well if the server PC were to crash, the client would never know. Ideally there you should have an application level Keepalive, for example Telnet command 0xFFF1, sent from both sides periodically to determine if the link is down, and to keep the connection active in any intermediate routers and firewalls. The TCP stack has an "SO_KEEPALIVE" option. An example of an application that can use this is the "Connection" configuration for PuTTY. The time for no activity before firing a keepalive is set by the registry entry "KeepAliveTime". The default is 2 hours which is too long, 300,000ms (5 minutes) is a good recommendation. I wouldn't want to venture below 1 minute. These keepalives should keep your connection active in any firewalls, and will alert your application if the connection is broken. This option is off by default and must be enabled on a per connection basis. Here's a "_TCPKeepAlive()" function that's a good fit for this UDF. @j0kky's use of Winsock API let me bluff my way around DllCall. expandcollapse popup; #FUNCTION# ==================================================================================================================== ; Name...........: _TCPKeepAlive ; Description ...: Set SO_KEEPALIVE Socket Option to enable stack level keepalive ; Syntax.........: _TCPKeepAlive($iMainsocket) ; Parameters ....: $iMainsocket - The array as returned by _TCPAccept ; or the connected socket identifier (SocketID) as returned by _TCPListen and _TCPConnect. ; Return values .: On success it returns: ; |0 - Success. ; On failure it returns -1 and sets @error to non zero: ; |-1 - internal error ; |-2 - missing DLL (Ws2_32.dll) ; |-3 - undefined error ; |Any Windows Socket Error Code retrieved by WSAGetLastError ; Author ........: TurionAltec ; Modified ......: 0.0.1 ; Remarks .......: KeepAlive will send a keepalive packet without sending any data. ; Some Firewalls may drop idle connections which can cause problems if a connection is quiet for an hour+ ; Can also be used to detect if the other end of a connection was dropped (computer abruptly powered off) ; ; Delay with no traffic before sending packet set globally from registry key: ; HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveTime ; Default is 7200000 (1 hour) Recommended is 300000 (5 minutes) ; ; "On Windows Vista and later, the SO_KEEPALIVE socket option can only be set using the setsockopt function ; when the socket is in a well-known state not a transitional state." ; ; Links .........: SO_KEEPALIVE: https://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx ; setsockopt function: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx ; KeepAliveTime Reg Entry: https://technet.microsoft.com/en-us/library/dd349797(v=ws.10).aspx#BKMK_2 ; =============================================================================================================================== Func _TCPKeepAlive($iMainsocket) If IsArray($iMainsocket) And (UBound($iMainsocket, 0) = 1) And (UBound($iMainsocket) > 0) Then $iMainsocket = $iMainsocket[0] Local $SOL_SOCKET = 0xffff Local $SO_KEEPALIVE = 0x0008 Local $hWs2 = DllOpen("Ws2_32.dll") If @error Then Return SetError(-2, 0, -1) ;missing DLL Local $bError = 0, $nCode = 0, $nExtended = 0 If Not $bError Then $aRet = DllCall($hWs2, "int", "setsockopt", "uint", $iMainsocket, "int", $SOL_SOCKET, "int", $SO_KEEPALIVE, "int*", 1, "int", 4) ;MSDN calls for "char*" not "int*", but DLLCall returns @Error=1 for char If @error Then $bError = -1 ElseIf $aRet[0] <> 0 Then ;SOCKET_ERROR $bError = 1 EndIf EndIf If $bError < 0 Then $nCode = -1 ;internal error $nReturn = -1 ;failure ElseIf $bError > 0 Then If Not $nCode Then $aRet = DllCall($hWs2, "int", "WSAGetLastError") If @error Then $nCode = -1 Else $nCode = $aRet[0] EndIf If $nCode = 0 Then $nCode = -3 ;undefined error EndIf If $nCode = -10 Then $nCode = 0 $nReturn = -1 Else $nReturn = $aRet EndIf DllClose($hWs2) Return SetError($nCode, 0, $nReturn) EndFunc ;==>_TCPKeepAlive KeepAliveTime.reg: Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] "KeepAliveTime"=dword:000493e0 ;Hex 493e0 = Decimal 300000 ;300,000 ms = 5 minutes I call _TCPKeepAlive() after _TCPAccept(), or _TCPConnect() return a good socket identifier. Note that MSDN says the sockets must not be in a transitional state… I found the included example scripts a little wonky, but below is a Wireshark Trace. I had sent the KeepAliveTime to 10 seconds for demonstration on the server, 10.0.0.2. "A TCP keep-alive packet is simply an ACK with the sequence number set to one less than the current sequence number for the connection. A host receiving one of these ACKs will respond with an ACK for the current sequence number." Now if only I can figure out how to set keepalive on sockets owned by another application! Edited November 27, 2017 by TurionAltec j0kky 1 Link to comment Share on other sites More sharing options...
Lecdev Posted February 5, 2018 Share Posted February 5, 2018 could this be extended to utilize the setsockopt winsock function to add to multicast groups and enable sending multicast packets? I'd be very interested in that. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now