Jump to content

TCPConnectTimeout function


funkey
 Share

Recommended Posts

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

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.

Link to comment
Share on other sites

  • 3 years later...
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

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

@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

My Contributions and Wrappers

Link to comment
Share on other sites

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

 

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.

Link to comment
Share on other sites

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

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

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

My Contributions and Wrappers

Link to comment
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
 Share

×
×
  • Create New...