Jump to content
funkey

TCPConnectTimeout function

Recommended Posts

funkey

Hello,
if an IP address is not reachable then TCPConnect lasts about 21 seconds for me the return with the error. Now I wrote a function using my socket_UDF to set a timeout if the IP address cannot be reached.
Have fun.


_TCPConnectTimeout example

#include "socket_UDF.au3"
Global $iTimerStart, $iSock
Global $TestIP = "1.2.3.4"
Global $TestPort = 800
Global $ConnectionTimeout = 1000
_WSAStartup()
Global $iTimerStart = TimerInit()
$iSock = _TCPConnectTimeout($TestIP, $TestPort, $ConnectionTimeout)
ConsoleWrite("_TCPConnectTimeout error: " & @error & " / new socket: " & $iSock & @CRLF)
ConsoleWrite("Function lasts: " & Round(TimerDiff($iTimerStart), 3) & @LF)
$iTimerStart = TimerInit()
$iSock = TCPConnect($TestIP, $TestPort)
ConsoleWrite("TCPConnect error: " & @error & " / new socket: " & $iSock & @CRLF)
ConsoleWrite("Function lasts: " & Round(TimerDiff($iTimerStart), 3) & @LF) ; about 21 seconds for me

_WSACleanup()
Exit
Func _TCPConnectTimeout($IP, $Port, $Timeout)
 Local Const $WSAEWOULDBLOCK = 10035
 Local $iSocket, $iResult, $tTimeout, $tWrite, $tErr
 $iSocket = _socket()
 If $iSocket = $SOCKET_ERROR Then Return SetError(1, 0, -1)
 $iResult = _ioctlsocket($iSocket, $FIONBIO, 1) ; nonblocking socket
 If $iResult <> 0 Then
  _closesocket($iSocket)
  Return SetError(2, 0, -1)
 EndIf
 $iResult = _connect($iSocket, $IP, $Port)
 If $iResult = $SOCKET_ERROR Then
  If _WSAGetLastError() = $WSAEWOULDBLOCK Then
   $tWrite = DllStructCreate($tagFd_set)
   $tErr = DllStructCreate($tagFd_set)
   _FD_SET($iSocket, $tWrite)
   _FD_SET($iSocket, $tErr)
   $iResult = _selectEx(0, DllStructGetPtr($tWrite), DllStructGetPtr($tErr), $Timeout)
   If $iResult <= 0 Then
    _closesocket($iSocket)
    Return SetError(3, 0, -1) ;timeout
   Else
    If Not _FD_ISSET($iSocket, $tWrite) Then
     _closesocket($iSocket)
     Return SetError(4, 0, -1) ; $tErr must have been set
    EndIf
   EndIf
  Else
   _closesocket($iSocket)
   Return SetError(5, 0, -1) ; another WSA error
  EndIf
 EndIf
 $iResult = _ioctlsocket($iSocket, $FIONBIO, 0) ; blocking socket again
 If $iResult <> 0 Then
  _closesocket($iSocket)
  Return SetError(6, 0, -1)
 EndIf
 Return $iSocket
EndFunc   ;==>_TCPConnectTimeout

socket_UDF

#include-once
; Some socket functions
; Author: funkey
; Project start 2013.03.12
; Actual project date 2013.08.27

Global Const $tagIN_ADDR = "ulong S_addr;"
Global Const $tagSockAddr = "USHORT sa_family;char sa_data[14]"
Global Const $tagSockAddr_In = "short sin_family;USHORT sin_port;ULONG sin_addr;char sin_zero[8]"
Global Const $tagSockAddr_Storage = "short ss_family;char ss_pad1[6];INT64 ss_align;char ss_pad1[112]"
Global Const $tagTimeVal = "long tv_sec;long tv_usec"
Global Const $tagAddrInfo = "int ai_flags;int ai_family;int ai_socktype;int ai_protocol;uint ai_addrlen;ptr ai_canonname;ptr ai_addr;ptr ai_next"
Global Const $FD_SETSIZE = 64
Global Const $tagFd_set = "UINT fd_count;UINT fd_array[" & $FD_SETSIZE & "]"
Global Const $AF_UNSPEC = 0
Global Const $AF_UNIX = 1
Global Const $AF_INET = 2
Global Const $AF_IMPLINK = 3
Global Const $AF_PUP = 4
Global Const $AF_CHAOS = 5
Global Const $AF_IPX = 6
Global Const $AF_NS = 6
Global Const $AF_ISO = 7
Global Const $AF_OSI = $AF_ISO
Global Const $AF_ECMA = 8
Global Const $AF_DATAKIT = 9
Global Const $AF_CCITT = 10
Global Const $AF_SNA = 11
Global Const $AF_DECnet = 12
Global Const $AF_DLI = 13
Global Const $AF_LAT = 14
Global Const $AF_HYLINK = 15
Global Const $AF_APPLETALK = 16
Global Const $AF_NETBIOS = 17
Global Const $AF_VOICEVIEW = 18
Global Const $AF_FIREFOX = 19
Global Const $AF_UNKNOWN1 = 20
Global Const $AF_BAN = 21
Global Const $AF_ATM = 22
Global Const $AF_INET6 = 23
Global Const $SOCKET_ERROR = -1
Global Const $INVALID_SOCKET = -1
Global Const $SOCK_STREAM = 1
Global Const $SOCK_DGRAM = 2
Global Const $SOCK_RAW = 3
Global Const $SOCK_RDM = 4
Global Const $SOCK_SEQPACKET = 5
Global Const $IPPROTO_IP = 0
Global Const $IPPROTO_ICMP = 1
Global Const $IPPROTO_IGMP = 2
Global Const $IPPROTO_GGP = 3
Global Const $IPPROTO_TCP = 6
Global Const $IPPROTO_PUP = 12
Global Const $IPPROTO_UDP = 17
Global Const $IPPROTO_IDP = 22
Global Const $IPPROTO_ND = 77
Global Const $IPPROTO_RAW = 255
Global Const $SOL_SOCKET = 0xFFFF
;SOL_SOCKET Socket Options
;http://msdn.microsoft.com/en-us/library/windows/desktop/ms740532(v=vs.85).aspx
Global Const $IP_OPTIONS = 1
Global Const $SO_DEBUG = 1
Global Const $SO_ACCEPTCONN = 2
Global Const $SO_REUSEADDR = 4 ; BOOLEAN
Global Const $SO_KEEPALIVE = 8
Global Const $SO_DONTROUTE = 16
Global Const $SO_BROADCAST = 32 ;INT
Global Const $SO_USELOOPBACK = 64
Global Const $SO_LINGER = 128
Global Const $SO_OOBINLINE = 256
Global Const $SO_EXCLUSIVEADDRUSE = -5 ; BOOLEAN  (~SO_REUSEADDR)
Global Const $SO_DONTLINGER = -129 ; (~SO_LINGER)
Global Const $SO_SNDBUF = 0x1001
Global Const $SO_RCVBUF = 0x1002
Global Const $SO_SNDLOWAT = 0x1003
Global Const $SO_RCVLOWAT = 0x1004
Global Const $SO_SNDTIMEO = 0x1005 ; DWORD
Global Const $SO_RCVTIMEO = 0x1006 ; DWORD
Global Const $SO_ERROR = 0x1007
Global Const $SO_TYPE = 0x1008
Global Const $FIONBIO = 0x8004667E
Global Const $FIONREAD = 0x4004667F
Global Const $FIOASYNC = 0x8004667D
Global Const $SIOCSHIWAT = 0x80047300
Global Const $SIOCGHIWAT = 0x80047301
Global Const $SIOCSLOWAT = 0x80047302
Global Const $SIOCGLOWAT = 0x80047303
Global Const $SIOCATMARK = 0x40047307
;max backlog for listen()
Global Const $SOMAXCONN = 0x7fffffff
;flags for send(to)
Global Const $MSG_DONTROUTE = 4
Global Const $MSG_OOB = 1
Global $hDLL_WS2_32 = 0
Func _WSAStartup()
 If $hDLL_WS2_32 = 0 Then
  $hDLL_WS2_32 = DllOpen("ws2_32.dll")
  If $hDLL_WS2_32 = -1 Then
   $hDLL_WS2_32 = 0
   Return 0
  EndIf
  If TCPStartup() = 0 Then ;TCPStartup() is equal to WSAStartup function
   DllClose($hDLL_WS2_32)
   $hDLL_WS2_32 = 0
   Return 0
  EndIf
 EndIf
 Return 1
EndFunc   ;==>_WSAStartup
Func _WSACleanup()
 If $hDLL_WS2_32 <> 0 Then
  TCPShutdown() ;TCPShutdown() is equal to WSACleanup function
  DllClose($hDLL_WS2_32)
  $hDLL_WS2_32 = 0
 EndIf
 Return 1
EndFunc   ;==>_WSACleanup

Func _setsockopt($iSocket, $iLevel, $iOptName, $tOptVal)
 Local $iOptLen = DllStructGetSize($tOptVal)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "setsockopt", "uint", $iSocket, "int", $iLevel, "int", $iOptName, "struct*", $tOptVal, "int", $iOptLen)
 Return $aRet[0]
EndFunc   ;==>_setsockopt
Func _getsockopt($iSocket, $iLevel, $iOptName, ByRef $tOptVal)
 Local $iOptLen = DllStructGetSize($tOptVal)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "setsockopt", "uint", $iSocket, "int", $iLevel, "int", $iOptName, "struct*", $tOptVal, "int", $iOptLen)
 Return $aRet[0]
EndFunc   ;==>_getsockopt
Func _socket($AF = $AF_INET, $SocketType = $SOCK_STREAM, $Protocol = $IPPROTO_TCP) ; AF_INET, SOCK_STREAM, IPPROTO_TCP
 Local $aRet = DllCall($hDLL_WS2_32, "int", "socket", "int", $AF, "int", $SocketType, "int", $Protocol)
 Return $aRet[0]
EndFunc   ;==>_socket
Func _closesocket($iSocket)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "closesocket", "UINT", $iSocket)
 Return $aRet[0]
EndFunc   ;==>_closesocket
;shutdown() allows you to cut off communication in a certain direction, or both ways (just like closesocket() does.)
;0 Further receives are disallowed
;1 Further sends are disallowed
;2 Further sends and receives are disallowed (like closesocket())
;It's important to note that shutdown() doesn't actually close the file descriptor — it just changes
;its usability. To free a socket descriptor, you need to use closesocket().
Func _shutdown($iSocket, $iHow)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "shutdown", "UINT", $iSocket, "int", $iHow)
 Return $aRet[0]
EndFunc   ;==>_shutdown
Func _bind($iSocket, $sIP, $iPort)
 Local $tSockAddr_In = DllStructCreate($tagSockAddr_In)
 Local $pSockAddr_In = DllStructGetPtr($tSockAddr_In)
 Local $iSizeSockAddr_In = DllStructGetSize($tSockAddr_In)
 DllStructSetData($tSockAddr_In, "sin_family", $AF_INET)
 DllStructSetData($tSockAddr_In, "sin_port", _htons($iPort))
 DllStructSetData($tSockAddr_In, "sin_addr", _inet_addr($sIP))
 Local $aRet = DllCall($hDLL_WS2_32, "int", "bind", "UINT", $iSocket, "struct*", $pSockAddr_In, "int", $iSizeSockAddr_In)
 Return $aRet[0]
EndFunc   ;==>_bind
Func _connect($iSocket, $sIP, $iPort)
 Local $tSockAddr_In = DllStructCreate($tagSockAddr_In)
 Local $iSizeSockAddr_In = DllStructGetSize($tSockAddr_In)
 DllStructSetData($tSockAddr_In, "sin_family", $AF_INET)
 DllStructSetData($tSockAddr_In, "sin_port", _htons($iPort))
 DllStructSetData($tSockAddr_In, "sin_addr", _inet_addr($sIP))
 Local $aRet = DllCall($hDLL_WS2_32, "int", "connect", "UINT", $iSocket, "struct*", $tSockAddr_In, "int", $iSizeSockAddr_In)
 Return $aRet[0]
EndFunc   ;==>_connect
Func _listen($iSocket, $iBacklog = $SOMAXCONN)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "listen", "UINT", $iSocket, "int", $iBacklog)
 Return $aRet[0]
EndFunc   ;==>_listen
Func _accept($iSocket, ByRef $sIP, ByRef $iPort)
 Local $tAddr = DllStructCreate($tagSockAddr_In)
 Local $aRet = DllCall($hDLL_WS2_32, "UINT", "accept", "UINT", $iSocket, "struct*", $tAddr, "int*", DllStructGetSize($tAddr))
 $iPort = _ntohs(DllStructGetData($tAddr, 2))
 $sIP = _inet_ntoa(DllStructGetData($tAddr, 3))
 Return $aRet[0]
EndFunc   ;==>_accept
Func _select(ByRef $tReadFds, $iTimeout)
 Local $tTimeout = DllStructCreate($tagTimeVal)
 DllStructSetData($tTimeout, "tv_sec", Floor($iTimeout / 1000))
 DllStructSetData($tTimeout, "tv_usec", ($iTimeout - DllStructGetData($tTimeout, "tv_sec") * 1000) * 1000)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "select", "int", 0, "struct*", $tReadFds, "ptr", 0, "ptr", 0, "struct*", $tTimeout)
 Return $aRet[0] ;-1 = error; 0 = timeout; else data!
EndFunc   ;==>_select
Func _selectEx($pReadFds, $pWriteFds, $pExceptFds, $iTimeout)
 Local $tTimeout = DllStructCreate($tagTimeVal)
 DllStructSetData($tTimeout, "tv_sec", Floor($iTimeout / 1000))
 DllStructSetData($tTimeout, "tv_usec", ($iTimeout - DllStructGetData($tTimeout, "tv_sec") * 1000) * 1000)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "select", "int", 0, "ptr", $pReadFds, "ptr", $pWriteFds, "ptr", $pExceptFds, "struct*", $tTimeout)
 Return $aRet[0] ;-1 = error; 0 = timeout; else data!
EndFunc   ;==>_selectEx
Func _FD_ZERO(ByRef $tFd_set)
 DllStructSetData($tFd_set, "fd_count", 0)
EndFunc   ;==>_FD_ZERO
Func _FD_SET($iSock, ByRef $tFd_set)
 Local $iCount = DllStructGetData($tFd_set, "fd_count")
 For $i = 0 To $iCount - 1
  If DllStructGetData($tFd_set, "fd_Array", $i + 1) = $iSock Then
   ExitLoop
  EndIf
 Next
 If $i = $iCount Then
  If $iCount < $FD_SETSIZE Then
   DllStructSetData($tFd_set, "fd_array", $iSock, $i + 1)
   DllStructSetData($tFd_set, "fd_count", $iCount + 1)
  EndIf
 EndIf
EndFunc   ;==>_FD_SET
Func _FD_CLR($iSock, ByRef $tFd_set)
 Local $iCount = DllStructGetData($tFd_set, "fd_count")
 For $i = 0 To $iCount - 1
  If DllStructGetData($tFd_set, "fd_array", $i + 1) = $iSock Then
   While ($i < $iCount - 1)
    DllStructSetData($tFd_set, "fd_array", DllStructGetData($tFd_set, "fd_array", $i + 2), $i + 1)
    $i += 1
   WEnd
  EndIf
  DllStructSetData($tFd_set, "fd_count", $iCount - 1)
  ExitLoop
 Next
EndFunc   ;==>_FD_CLR
Func _FD_ISSET($iSock, ByRef $tFd_set)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "__WSAFDIsSet", "UINT", $iSock, "struct*", $tFd_set)
 Return $aRet[0]
EndFunc   ;==>_FD_ISSET
Func _send($iSocket, ByRef $tBuffer, $iFlags = 0)
 Local $iLen = DllStructGetSize($tBuffer)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "send", "int", $iSocket, "struct*", $tBuffer, "int", $iLen, "int", $iFlags)
 Return $aRet[0]
EndFunc   ;==>_send
Func _sendto($iSocket, ByRef $tBuffer, ByRef $tTo, $iFlags = 0)
 Local $iLen = DllStructGetSize($tBuffer)
 Local $iLenTo = DllStructGetSize($tTo)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "sendto", "int", $iSocket, "struct*", $tBuffer, "int", $iLen, "int", $iFlags, "struct*", $tTo, "int", $iLenTo)
 Return $aRet[0]
EndFunc   ;==>_sendto
Func _recv($iSocket, ByRef $tBuffer, $iFlags = 0)
 Local $iLen = DllStructGetSize($tBuffer)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "recv", "uint", $iSocket, "struct*", $tBuffer, "int", $iLen, "int", $iFlags)
 Return $aRet[0]
EndFunc   ;==>_recv
Func _recvfrom($iSocket, ByRef $tBuffer, ByRef $tFrom, $iFlags = 0)
 Local $iLen = DllStructGetSize($tBuffer)
 Local $iLenFrom = DllStructGetSize($tFrom)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "recvfrom", "uint", $iSocket, "struct*", $tBuffer, "int", $iLen, "int", $iFlags, "struct*", $tFrom, "int", $iLenFrom)
 Return $aRet[0]
EndFunc   ;==>_recvfrom
Func _inet_addr($sIP)
 Local $aRet = DllCall($hDLL_WS2_32, "ULONG", "inet_addr", "str", $sIP)
 Return $aRet[0]
EndFunc   ;==>_inet_addr
Func _inet_ntoa($pIn_Addr) ;only IPv4 (deprecated) --> use _inet_ntop() instead
 Local $aRet = DllCall($hDLL_WS2_32, "str", "inet_ntoa", "ptr", $pIn_Addr)
 Return $aRet[0]
EndFunc   ;==>_inet_ntoa
Func _inet_ntop($pIn_Addr, $iFamily = $AF_INET) ;IPv4 and IPv6 --> Vista and above
 Local $tBuffer = DllStructCreate("char[46]") ;16 for IPv4, 46 for IPv6
 Local $aRet = DllCall($hDLL_WS2_32, "str", "inet_ntop", "int", $iFamily, "ptr", $pIn_Addr, "struct*", $tBuffer, "int", DllStructGetSize($tBuffer))
 Return DllStructGetData($tBuffer, 1)
EndFunc   ;==>_inet_ntop
;host byte order to network byte order (double)
Func _htond($value)
 Local $aRet = DllCall($hDLL_WS2_32, "UINT64", "htond", "double", $value)
 Return $aRet[0]
EndFunc   ;==>_htond
;host byte order to network byte order (float)
Func _htonf($value)
 Local $aRet = DllCall($hDLL_WS2_32, "UINT", "htonf", "float", $value)
 Return $aRet[0]
EndFunc   ;==>_htonf
;host byte order to network byte order (long)
Func _htonl($value)
 Local $aRet = DllCall($hDLL_WS2_32, "ULONG", "htonl", "ULONG", $value)
 Return $aRet[0]
EndFunc   ;==>_htonl
;host byte order to network byte order (long long)
Func _htonll($value)
 Local $aRet = DllCall($hDLL_WS2_32, "UINT64", "htonll", "UINT64", $value)
 Return $aRet[0]
EndFunc   ;==>_htonll
;host byte order to network byte order (short)
Func _htons($iPort)
 Local $aRet = DllCall($hDLL_WS2_32, "USHORT", "htons", "USHORT", $iPort)
 Return $aRet[0]
EndFunc   ;==>_htons
;network byte order to host byte order (double)
Func _ntohd($value)
 Local $aRet = DllCall($hDLL_WS2_32, "double", "ntohd", "UINT64", $value)
 Return $aRet[0]
EndFunc   ;==>_ntohd
;network byte order to host byte order (float)
Func _ntohf($value)
 Local $aRet = DllCall($hDLL_WS2_32, "float", "ntohf", "UINT", $value)
 Return $aRet[0]
EndFunc   ;==>_ntohf
;network byte order to host byte order (long)
Func _ntohl($iNetLong)
 Local $aRet = DllCall($hDLL_WS2_32, "ULONG", "ntohl", "ULONG", $iNetLong)
 Return $aRet[0]
EndFunc   ;==>_ntohl
;network byte order to host byte order (long long)
Func _ntohll($value)
 Local $aRet = DllCall($hDLL_WS2_32, "UINT64", "ntohll", "UINT64", $value)
 Return $aRet[0]
EndFunc   ;==>_ntohll
;network byte order to host byte order (short)
Func _ntohs($iNetShort)
 Local $aRet = DllCall($hDLL_WS2_32, "USHORT", "ntohs", "USHORT", $iNetShort)
 Return $aRet[0]
EndFunc   ;==>_ntohs
Func _WSAGetLastError()
 Local $aRet = DllCall($hDLL_WS2_32, "int", "WSAGetLastError")
 Return $aRet[0]
EndFunc   ;==>_WSAGetLastError

Func _GetLocalPort($iSocket)
 ;funkey
 Local $tagIN_ADDR = "ulong S_addr;"
 Local $tagSockAddr_In = "short sin_family;ushort sin_port;ptr sin_addr;char sin_zero[8];"
 Local $tIn_Addr = DllStructCreate($tagIN_ADDR)
 Local $tName = DllStructCreate($tagSockAddr_In)
 DllStructSetData($tName, "sin_addr", DllStructGetPtr($tIn_Addr))
 Local $aRes = DllCall($hDLL_WS2_32, "int", "getsockname", "uint", $iSocket, "struct*", $tName, "int*", 512)
 Local $aRes2 = DllCall($hDLL_WS2_32, "ushort", "ntohs", "ushort", DllStructGetData($tName, 2))
 Return $aRes2[0]
EndFunc   ;==>_GetLocalPort
Func _getsockname($iSocket)
 Local $tIn_Addr = DllStructCreate($tagIN_ADDR)
 Local $tName = DllStructCreate($tagSockAddr_In)
 DllStructSetData($tName, "sin_addr", DllStructGetPtr($tIn_Addr))
 Local $aRes[2]
 Local $aRet = DllCall($hDLL_WS2_32, "int", "getsockname", "uint", $iSocket, "struct*", $tName, "int*", 512)
 If Not @error And $aRet[0] = 0 Then
  $aRes[0] = _inet_ntoa(DllStructGetData($tName, "sin_addr")) ;IP address
  $aRes[1] = _ntohs(DllStructGetData($tName, "sin_port")) ;IP port
;~   $aRes[2] = DllStructGetData($tName, "sin_family") ; always AF_INET !?
  Return $aRes
 EndIf
 Return SetError(1, 0, 0)
EndFunc   ;==>_getsockname
;More than TCPNameToIP(), returns an array of IP addresses
Func _getaddrinfo($sNodeName)
 Local $pResult, $tAddrInfo, $sIP
 Local $aRet = DllCall($hDLL_WS2_32, "int", "getaddrinfo", "str", $sNodeName, "ptr", 0, "ptr", 0, "ptr*", 0)
 $pResult = $aRet[4]
 Do
  $tAddrInfo = DllStructCreate($tagAddrInfo, $pResult)
  Local $tName = DllStructCreate($tagSockAddr_In, DllStructGetData($tAddrInfo, "ai_addr"))
  $sIP &= _inet_ntoa(DllStructGetData($tName, "sin_addr")) & ";"
  $pResult = DllStructGetData($tAddrInfo, "ai_next")
 Until $pResult = 0
 _freeaddrinfo($aRet[4])
 Return StringSplit(StringTrimRight($sIP, 1), ";", 2)
EndFunc   ;==>_getaddrinfo
Func _freeaddrinfo($pAddrInfo)
 DllCall($hDLL_WS2_32, "none", "freeaddrinfo", "ptr", $pAddrInfo)
EndFunc   ;==>_freeaddrinfo
Func _ioctlsocket($iSocket, $iCmd, $iArg)
 Local $aRet = DllCall($hDLL_WS2_32, "int", "ioctlsocket", "uint", $iSocket, "long", $iCmd, "ULONG*", $iArg)
 Return $aRet[0]
EndFunc   ;==>_ioctlsocket
Func _TCPConnectEx($sIP, $iRemPort, $iRcvTimeOut = 0, $iSendTimeOut = 0, $iLocPort = -1)
 Local $tTimeVal, $iSockError, $iBind, $iConnect, $aIP[1]
 Local $iSock = _socket($AF_INET, $SOCK_STREAM, $IPPROTO_TCP)
 If $iRcvTimeOut > 0 Then
  $tTimeVal = DllStructCreate("DWORD timeout")
  DllStructSetData($tTimeVal, "timeout", $iRcvTimeOut)
  $iSockError = _setsockopt($iSock, $SOL_SOCKET, $SO_RCVTIMEO, $tTimeVal)
  If $iSockError Then
   _closesocket($iSock)
   Return SetError(1, _WSAGetLastError(), 0)
  EndIf
 EndIf
 If $iSendTimeOut > 0 Then
  $tTimeVal = DllStructCreate("DWORD timeout")
  DllStructSetData($tTimeVal, "timeout", $iSendTimeOut)
  $iSockError = _setsockopt($iSock, $SOL_SOCKET, $SO_SNDTIMEO, $tTimeVal)
  If $iSockError Then
   _closesocket($iSock)
   Return SetError(2, _WSAGetLastError(), 0)
  EndIf
 EndIf
 If $iLocPort >= 0 Then
  $iBind = _bind($iSock, @IPAddress1, $iLocPort)
  If $iBind Then
   _closesocket($iSock)
   Return SetError(3, _WSAGetLastError(), 0)
  EndIf
 EndIf
 If _IsValidIP($sIP) Then
  $aIP[0] = $sIP
 Else
  $aIP = _getaddrinfo($sIP)
 EndIf
 $iConnect = _connect($iSock, $aIP[0], $iRemPort)
 If $iConnect Then
  _closesocket($iSock)
  Return SetError(4, _WSAGetLastError(), 0)
 EndIf
 Return $iSock
EndFunc   ;==>_TCPConnectEx

Func _IsValidIP($sIP)
 Local $aIP = StringSplit($sIP, ".")
 If $aIP[0] <> 4 Then Return SetError(1, 0, 0)
 For $x = 1 To $aIP[0]
  If $aIP[$x] < 0 Or $aIP[$x] > 255 Then Return SetError(2, 0, 0)
 Next
 Return 1
EndFunc   ;==>_IsValidIP

TCPConnectTimeout & socket UDF.rar

Edited by funkey
  • Like 1

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Share this post


Link to post
Share on other sites
argumentum
On 8/27/2013 at 11:56 AM, funkey said:

_getsockopt

Hi @funkey, I was looking for the optimum TCP MaxLen for TCPRecv , getsockopt() would be it. But there is no example of use in the provided files nor a simple "getsockopt()" call that would return the size, On top of all that, I may have no idea of what or how to ask.
Also, now that I looked at https://www.autoitscript.com/forum/topic/181645-winsock-udf/ from @j0kky, your code may be wrong in that function, as is the same as setsockopt() .
Any answer from anyone is welcomed, as I'd like to know why the default 1024 when MTU is usually 1500, but .... all these are way over my head. Still wanna know if there is a way to ask the OS for a optimum value.

Edit: maybe RegRead("HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters","TcpWindowSize") gives the value ?, if so, would it work on the internet as well as LAN ?

Edited by argumentum

Share this post


Link to post
Share on other sites
RTFC

@argumentum: Have a look at _Pool_SetTCPsocketOptions in my Pool environment, and the associated constants. Be careful not to confuse the size of the MTU with the size of the TCP buffer, which can hold multiple MTUs. I use:

Quote

Global Const $_POOL_MTU_TCP        =576        ; for our purposes; on Ethernet 1,472 bytes
Global Const $_POOL_MTU_TCPBUFFER=0x4470    ; Ethernet; theoretical max: 0xffff; see also HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ <interface-name>

AFAIK, 1472 bytes is the max packet size on LAN. To be honest, my fading brain :huh2::idiot:has trouble recalling where I derived the (multiple-MTU) buffer size of 0x4470h, but the way to figure it out for your system would be to repeatedly call setsockopt followed by getsockopt (to evaluate whether the call was successful) with ever larger buffer sizes, until it fails.

EDIT: See also here and here. And see my _Pool_Client_Received for an example of how to deal with packet fragmentation. Hope this helps.:)

Edited by RTFC
  • Like 1

Share this post


Link to post
Share on other sites
funkey

Maybe I never used this function? I don't even know!

Here an example:

 

Global Const $SO_SNDBUF = 0x1001
Global Const $SO_RCVBUF = 0x1002

Global Const $SOL_SOCKET = 0xFFFF

Global Const $SO_MAX_MSG_SIZE = 0x2003

Global $Domain = "www.google.com"

TCPStartup()

Global $IP = TCPNameToIP($Domain)

Global $iSock = TCPConnect($IP, 80)
If $iSock = -1 Then
    ConsoleWrite("Connection error!" & @CRLF)
    Exit
EndIf

Global $tResult = DllStructCreate("int")

Global $iRes = _getsockopt($iSock, $SOL_SOCKET, $SO_SNDBUF, $tResult)
If $iRes = 0 Then
    ConsoleWrite("send buffer size = " & DllStructGetData($tResult, 1) & @CRLF)
EndIf

Global $iRes = _getsockopt($iSock, $SOL_SOCKET, $SO_RCVBUF, $tResult)
If $iRes = 0 Then
    ConsoleWrite("receive buffer size = " & DllStructGetData($tResult, 1) & @CRLF)
EndIf

TCPCloseSocket($iSock)


Func _getsockopt($iSocket, $iLevel, $iOptName, ByRef $tOptVal)
    Local $iOptLen = DllStructGetSize($tOptVal)
    Local $aRet = DllCall("WS2_32.DLL", "int", "getsockopt", "int", $iSocket, "int", $iLevel, "int", $iOptName, "struct*", $tOptVal, "int*", $iOptLen)
    Return $aRet[0]
EndFunc ;==>_getsockopt

 

  • Like 1

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Share this post


Link to post
Share on other sites
argumentum

@funkey, thanks a million, this exactly what I wanted.
@RTFC, in https://en.wikipedia.org/wiki/Maximum_transmission_unit , they give a nice explanation ( nice becouse is dumbed down for me ;) ), where I gather that I should use the value of _getsockopt(), that in my case is 8192 ( in 2 XPs and 1 Win7 ) and deduct 22 bytes of protocol overhead and use that, 8170,  for MaxLen.
Also in the example for TCPRecv in the AutoIt manual, a 4k size is used in the 2nd example ( send file ) , but I'd use the 8170 chunks ( _getsockopt() - 22 ). That should ensure maximum transmission speed.

Although, thinking about it, I might as well say " I'll take 64k" ( as maxLen ), because the idea is to send in a way that is not fragmented, whatever came in, came in. 

Do correct me if my brainstorming is flawed :)

Share this post


Link to post
Share on other sites
RTFC

@argumentum: Hmmm, a few off-the-cuff remarks...:mellow:

2 hours ago, argumentum said:

I should use the value of _getsockopt(),

This will return whatever it was most recently successfully set to by any other software, and does not necessarily reflect full capacity on your system.

2 hours ago, argumentum said:

I might as well say " I'll take 64k" ( as maxLen )

I don't think that'll work. If you call getsockopt with a value that's too high, the call will simply fail (in my experience). That's why you should call getsockopt afterwards to check whether setsockopt succeeded. Plus, from a machine-code perspective, setting any capacity to (2^n) -1 is asking for trouble (read: buffer overflow/inadvertent wrap/page fault/etc...).:wacko:

 

2 hours ago, argumentum said:

the idea is to send in a way that is not fragmented, whatever came in, came in.

Great idea,:lol: but reality tends to be messier.:x Will you be able to ensure that your Recv capacity will always exceed the Send load on your chosen port? How about if the hardware layer(s) underneath the TCP layer start running out of buffer space (e.g., due to a memory leak) or may themselves collect multiple packets before a flush (which then may exceed the capacity of your own buffer)? I would suggest you at least consider in your message handling that your socket buffer may at some point be filled completely before you get a chance to deal with it, with more data on the way/waiting in the wings. It may also be beneficial to make the buffer an exact multiple of your (fixed) packet size, so you won't have to rebuild packets from split fragments. All I'm saying is, you do not have full control over the hardware layers, so your software layer(s) should have contingency planning built in.:whistle:

That being said, 8K minus overhead sounds like a reasonable size to play with. But I would use a bit more overhead (maybe subtract 10% from maxlen, with a minimum of 128 bytes, or maybe one full packet size).

Note also that if you were to use VPN to access your LAN (for example), VPN itself will add another header to your packet. It's stuff like that you discover only once you start chasing "impossible bugs." On top of that, these tend to be Heisenbugs, i.e., highly timing- and capacity-sensitive, and thus very difficult to hunt down and kill.:rambo: Best not to invite those to your party...

  • Like 1

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • Blueman
      By Blueman
      Hi all,
      I was wondering if you can help me with the function called; InetRead().
      My scripts are using this function a lot for several conditions and everything works fine!
      But sometimes when the server is a little bit buggy of simply not available my script is hanging.
      It takes about 90sec before this function returns a Timeout, when i adjust the parameter it still is hanging about 90sec.
      The following script is a example where the script is hanging for aprox. 90sec;
      ; Set Timeout to 2sec AutoItSetOption ("TCPTimeout", 2000) ; Read Website InetRead("http://www.geenverbinding.nl/",1) ; Show Msgbox before Ending Script. Msgbox(64,"","Finished")  
      The following script is a example where the script show the Msgbox pretty fast;

       
      ; Set Timeout to 2sec AutoItSetOption ("TCPTimeout", 2000) ; Read Website InetRead("http://www.google.nl/",1) ; Show Msgbox before Ending Script. Msgbox(64,"","Finished")  
      My question now is, what am i doing wrong and/or is there a other way to prevent Hanging the script?
      Thanks all
       
    • ur
      By ur
      I have automated an install process by using the below code.
       
      Func _WinWaitActivate($title,$text,$timeout=0) WinWait($title,$text,$timeout) If Not WinActive($title,$text) Then WinActivate($title,$text) WinWaitActive($title,$text,$timeout) EndFunc $win1 = "Text 1" $win2 = "Text 2" _WinWaitActivate($win1,"WARNING: This progra") Send("{ALTDOWN}n{ALTUP}");Send("{SPACE}") _WinWaitActivate($win1,"I DISAGREE and &do n") Send("{UP}n") _WinWaitActivate($win1,"Customer Information") Send("{ALTDOWN}n{ALTUP}");Send("{TAB}{TAB}n") _WinWaitActivate($win1,"Click Next to instal") Send("{ALTDOWN}n{ALTUP}");Send("n") _WinWaitActivate($win1,"This feature require") Send("{ALTDOWN}n{ALTUP}");Send("{TAB}n") _WinWaitActivate($win1,"Ready to Install the") Send("{ALTDOWN}i{ALTUP}");Send("i") _WinWaitActivate($win1,"The InstallShield Wi") Send("{ALTDOWN}f{ALTUP}");Send("f") _WinWaitActivate($win2,"You must restart you") Send("{ALTDOWN}n{ALTUP}");Send("n") Now if any new screen comes in the middle of installation, like some VC++ installation error or like that.
      The AutoIT is waiting in the background.
      Is there any way to skip the new screens with just "enter" and continue the installation??
    • Spyderco
      By Spyderco
      Hi everyone

      I'll explain what I'm trying to achieve briefly:

      I run several websites and am running pilots for a new framework on a few server.
      I have a certain script set us like a bunch of checkboxes, one of which checks a URL for it's status response set to a $ClientURL variable.
      So I have something like the following:

      Set includes
      Set variables (one of which is $ClientURL = ("www.example.com").
      Start loop
         Main script
            If $ClientURL = ("www.example.com") Then
                $ClientURL = ("www.a.com")
            If $ClientURL = ("www.a.com") Then
               $ClientURL = ("www.b.com")
            ElseIf $ClientURL = ("www.b.com") Then
               $ClientURL = ("www.c.com")
            ElseIf $ClientURL = ("www.c.com") Then
               $ClientURL = ("www.d.com")
            ElseIf $ClientURL = ("www.c.com") Then
               $ClientURL = ("www.example.com")
            Sleep until the script restarts the loop.
      End loop

      This only uses one main script and changes the variables needed to run in by the following value every time.
      My problem is this...
      Everything runs smoothly, but if a webserver takes too long to respond, the program will timeout.
      This doesn't give a certain status, so it doesn't get logged by the script so it can move on to the next one.
      It just freezes and crashes on it eventually.
      Is there a way to add a certain timeout to a line?
      Lets say something like this:
      Func A ()
      $oHTTP = ObjCreate("winhttp.winhttprequest.5.1")
      $oHTTP.Open("GET", $ClientURL, False)
      $oHTTP.Send()
      If the time it takes = >10 seconds
         Move on to the next line
      Else
         Do nothing
      EndFunc

      I thought about making a variable that tracks the system time in seconds that has passed by and resets it at the beginning of every new function,
      but I was hoping there'd be something more efficient...
      Thanks in advance guys!
    • explorerpl
      By explorerpl
      Hi. I'm a teacher and I do a lot of tutorials and other presentations on my computer. I've developed a tool using AutoIt and Adobe AIR to display all the shortcuts I use while I'm presenting. According to the forum rules this would mean that I've developed a keylogger, so I can't show any of the code, but I'm still hoping someone will help me solve an issue I'm having - a memory leak (or at least I think that's it).
      I can see the application is taking up more and more memory, but it never goes super crazy. I think it was at 25 MB at one point and that was it. However I see that the longer the application is running less responsive it is. It doesn't capture all the events, or it simply lags. 
      I'm using AssocArrays and _MouseOnEvent UDFs, _WinAPI_SetTimer, _WinAPI_SetWindowsHookEx, _Singleton and TCP. I've done some research before posting this and I know there are some issues in special cases, but all solutions were "code specific". Since I can't post any of the code I couldn't respond in those threads. Other than that it really doesn't seem to be the problem with any of the UDFs, so my question is:
      Is this a memory leak? If so how can I find it and remove it? What to do to avoid it in the future.
      I understand that declaring variables over and over (something in the timer) may be the cause of this, so according to what I've read on the forum I've changed the variables to Global and moved them outside the functions. That way they are only declared once, and then only values are being reassigned. That unfortuantly didn't help. Is there anything else I could do or look for?
      BTW - I've used Adobe AIR to create a nice UI. If someone want's to create something similar UEZ was kind enough to share his code of creating such GUI with nice antialiased labels. 
      https://www.autoitscript.com/forum/topic/178366-adobe-air-like-window/#comment-1280587

    • algiuxas
      By algiuxas
      Hello, I have a problem, I downloaded example of TCP Server and Client, but client doesn't work, It shows TCPConnect 10060 error (timeout), I tried to turn on two servers, I think server work, because one server show 10048 error(Address already in use) I don't know why it doesn't work, I edited that script, but it doesn't work still. I tried TCPConnect and TCPAccept from AutoIt3\Examples\Helpfile, but TCPConnect shows error 10060(timeout)... Anybody knows how to fix it? Thanks
      ; SERVER #include <Array.au3> TCPStartup() Dim $Socket_Data[1] $Socket_Data[0] = 0 $Listen = TCPListen(@IPAddress1, 1018, 500) If @error Then ConsoleWrite('!-->['&@Hour&":"&@MIN&":"&@SEC&'] TCPListen error. ( ' & @error & ' )' & @CRLF) Exit EndIf While 1 For $x = $Socket_Data[0] To 1 Step -1 $Recv = TCPRecv($Socket_Data[$x], 1000000) If $Recv Then MsgBox(0, 'Client Number ' & $x & ' with connected socket identifier ' & $Socket_Data[$x], "["&@Hour&":"&@MIN&":"&@SEC&"]"&' Recived msg from Client: ' & @CRLF & $Recv, 5) TCPSend($Socket_Data[$x], 'bye') TCPCloseSocket($Socket_Data[$x]) _ArrayDelete($Socket_Data, $x) $Socket_Data[0] -= 1 EndIf Next _Accept() WEnd Func _Accept() Local $Accept = TCPAccept($Listen) If $Accept <> -1 Then _ArrayAdd($Socket_Data, $Accept) $Socket_Data[0] += 1 EndIf EndFunc ;==>_Accept exit ; CLIENT $Connected = False TCPStartup() ; Start TCP. $timespentconnecting = TimerInit( ) Do $Socket = TCPConnect(@IPAddress1, 1018) ; Connect to server. $nERROR = @error ; TCPConnect @error. If not $nERROR Then ; If client connected to server. $Connected = True Else ; If TCPConnect didn't connected to server. ConsoleWrite( "["&@Hour&":"&@MIN&":"&@SEC&"] TCPConnect error. {CODE:" & $nERROR & "}"&@CRLF ) ; Show error. EndIf sleep(100) ; Sleep 0.1 secounds. Until $Connected = True or TimerDiff( $timespentconnecting ) > 10000 ; If client connected or timer > 10 secounds, stop trying connect to server. If $Connected = False then exit ; If client didn't connected to server, exit. TCPSend($Socket, 'Hi there. My computer name is' & ", " & @ComputerName & ", and its drive serial is " & DriveGetSerial(@HomeDrive)); Send to server data. Do ; Loop until client recives data from server. $Recv = TCPRecv($Socket, 1000000) ; Recive data from server. Until $Recv ; Stop looping when data recived from server. MsgBox(0, "["&@Hour&":"&@MIN&":"&@SEC&"] Recived from server:", $Recv); Show recived data from server. Exit(0) ; Exit.  
×