4 Persistable =
0 'NotPersistable
5 DataBindingBehavior =
0 'vbNone
6 DataSourceBehavior =
0 'vbNone
7 MTSTransactionMode =
0 'NotAnMTSObject
9 Attribute VB_Name = "CSocketMaster"
10 Attribute VB_GlobalNameSpace = False
11 Attribute VB_Creatable = True
12 Attribute VB_PredeclaredId = False
13 Attribute VB_Exposed = False
14 '********************************************************************************
16 'Name.......... CSocketMaster
17 'File.......... CSocketMaster.cls
19 'Dependencies.. Requires modSocketMaster.bas code module
20 'Description... Winsock api implementation class
21 'Author........ Emiliano Scavuzzo <anshoku@yahoo.com>
22 'Date.......... June,
28th
2004
23 'Copyright (c)
2004 by Emiliano Scavuzzo
26 'Based on CSocket by Oleg Gdalevich
27 'Subclassing based on WinSubHook2 by Paul Caton <Paul_Caton@hotmail.com>
29 '********************************************************************************
31 '==============================================================================
33 '==============================================================================
34 Private Declare Function api_socket _
36 Alias "socket" (ByVal af As Long, _
37 ByVal s_type As Long, _
38 ByVal Protocol As Long) As Long
39 Private Declare Function api_GlobalLock _
41 Alias "GlobalLock" (ByVal hMem As Long) As Long
42 Private Declare Function api_GlobalUnlock _
44 Alias "GlobalUnlock" (ByVal hMem As Long) As Long
45 Private Declare Function api_htons _
47 Alias "htons" (ByVal hostshort As Integer) As Integer
48 Private Declare Function api_ntohs _
50 Alias "ntohs" (ByVal netshort As Integer) As Integer
51 Private Declare Function api_connect _
53 Alias "connect" (ByVal s As Long, _
54 ByRef name As sockaddr_in, _
55 ByVal namelen As Long) As Long
56 Private Declare Function api_gethostname _
58 Alias "gethostname" (ByVal host_name As String, _
59 ByVal namelen As Long) As Long
60 Private Declare Function api_gethostbyname _
62 Alias "gethostbyname" (ByVal host_name As String) As Long
63 Private Declare Function api_bind _
65 Alias "bind" (ByVal s As Long, _
66 ByRef name As sockaddr_in, _
67 ByVal namelen As Long) As Long
68 Private Declare Function api_getsockname _
70 Alias "getsockname" (ByVal s As Long, _
71 ByRef name As sockaddr_in, _
72 ByRef namelen As Long) As Long
73 Private Declare Function api_getpeername _
75 Alias "getpeername" (ByVal s As Long, _
76 ByRef name As sockaddr_in, _
77 ByRef namelen As Long) As Long
78 Private Declare Function api_inet_addr _
80 Alias "inet_addr" (ByVal cp As String) As Long
81 Private Declare Function api_send _
83 Alias "send" (ByVal s As Long, _
85 ByVal buflen As Long, _
86 ByVal flags As Long) As Long
87 Private Declare Function api_sendto _
89 Alias "sendto" (ByVal s As Long, _
91 ByVal buflen As Long, _
92 ByVal flags As Long, _
93 ByRef toaddr As sockaddr_in, _
94 ByVal tolen As Long) As Long
95 Private Declare Function api_getsockopt _
97 Alias "getsockopt" (ByVal s As Long, _
98 ByVal level As Long, _
99 ByVal optname As Long, _
101 optlen As Long) As Long
102 Private Declare Function api_setsockopt _
104 Alias "setsockopt" (ByVal s As Long, _
105 ByVal level As Long, _
106 ByVal optname As Long, _
108 ByVal optlen As Long) As Long
109 Private Declare Function api_recv _
111 Alias "recv" (ByVal s As Long, _
113 ByVal buflen As Long, _
114 ByVal flags As Long) As Long
115 Private Declare Function api_recvfrom _
117 Alias "recvfrom" (ByVal s As Long, _
119 ByVal buflen As Long, _
120 ByVal flags As Long, _
121 ByRef from As sockaddr_in, _
122 ByRef fromlen As Long) As Long
123 Private Declare Function api_WSACancelAsyncRequest _
125 Alias "WSACancelAsyncRequest" (ByVal hAsyncTaskHandle As Long) As Long
126 Private Declare Function api_listen _
128 Alias "listen" (ByVal s As Long, _
129 ByVal backlog As Long) As Long
130 Private Declare Function api_accept _
132 Alias "accept" (ByVal s As Long, _
133 ByRef addr As sockaddr_in, _
134 ByRef addrlen As Long) As Long
135 Private Declare Function api_inet_ntoa _
137 Alias "inet_ntoa" (ByVal inn As Long) As Long
138 Private Declare Function api_ioctlsocket _
140 Alias "ioctlsocket" (ByVal s As Long, _
142 ByRef argp As Long) As Long
143 Private Declare Function api_closesocket _
145 Alias "closesocket" (ByVal s As Long) As Long
146 'Private Declare Function api_gethostbyaddr Lib "ws2_32.dll" Alias "gethostbyaddr" (addr As Long, ByVal addr_len As Long, ByVal addr_type As Long) As Long
147 '==============================================================================
149 '==============================================================================
150 Public Enum SockState
162 Private Const SOMAXCONN As Long =
5
163 Public Enum ProtocolConstants
167 Private Const MSG_PEEK As Long = &H2
168 '==============================================================================
170 '==============================================================================
171 Public Event CloseSck()
172 Public Event Connect()
173 Public Event ConnectionRequest(ByVal requestID As Long)
174 Public Event DataArrival(ByVal bytesTotal As Long)
175 Public Event error(ByVal Number As Integer, Description As String, ByVal sCode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
176 Public Event SendComplete()
177 Public Event SendProgress(ByVal bytesSent As Long, ByVal bytesRemaining As Long)
178 '==============================================================================
180 '==============================================================================
181 Private m_lngSocketHandle As Long 'socket handle
182 Private m_enmState As SockState 'socket state
183 Private m_strTag As String 'tag
184 Private m_strRemoteHost As String 'remote host
185 Private m_lngRemotePort As Long 'remote port
186 Private m_strRemoteHostIP As String 'remote host ip
187 Private m_lngLocalPort As Long 'local port
188 Private m_lngLocalPortBind As Long 'temporary local port
189 Private m_strLocalIP As String 'local IP
190 Private m_enmProtocol As ProtocolConstants 'protocol used (TCP / UDP)
191 Private m_lngMemoryPointer As Long 'memory pointer used as buffer when resolving host
192 Private m_lngMemoryHandle As Long 'buffer memory handle
193 Private m_lngSendBufferLen As Long 'winsock buffer size for sends
194 Private m_lngRecvBufferLen As Long 'winsock buffer size for receives
195 Private m_strSendBuffer As String 'local incoming buffer
196 Private m_strRecvBuffer As String 'local outgoing buffer
197 Private m_blnAcceptClass As Boolean 'if True then this is an Accept socket class
198 Private m_colWaitingResolutions As Collection 'hosts waiting to be resolved by the system
200 ' **** WARNING WARNING WARNING WARNING ******
201 'This sub MUST be the first on the class. DO NOT attempt
202 'to change it's location or the code will CRASH.
203 'This sub receives system messages from our WndProc.
204 Public Sub WndProc(ByVal hWnd As Long, _
205 ByVal uMsg As Long, _
206 ByVal wParam As Long, _
207 ByVal lParam As Long)
209 On Error GoTo WndProc_Err
215 PostResolution wParam, HiWord(lParam)
218 PostSocket LoWord(lParam), HiWord(lParam)
224 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.WndProc"
229 Private Sub Class_Initialize()
230 'socket's handle default value
232 On Error GoTo Class_Initialize_Err
234 m_lngSocketHandle = INVALID_SOCKET
235 'initiate resolution collection
236 Set m_colWaitingResolutions = New Collection
237 'initiate processes and winsock service
238 modSocketMaster.InitiateProcesses
241 Class_Initialize_Err:
242 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Class_Initialize"
247 Private Sub Class_Terminate()
248 'clean hostname resolution system
252 CleanResolutionSystem
254 'destroy socket if it exists
255 If Not m_blnAcceptClass Then DestroySocket
256 'clean processes and finish winsock service
257 modSocketMaster.FinalizeProcesses
258 'clean resolution collection
259 Set m_colWaitingResolutions = Nothing
262 '==============================================================================
264 '==============================================================================
265 Public Property Get RemotePort() As Long
267 On Error GoTo RemotePort_Err
269 RemotePort = m_lngRemotePort
273 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.RemotePort"
278 Public Property Let RemotePort(ByVal lngPort As Long)
280 On Error GoTo RemotePort_Err
283 If m_enmProtocol = sckTCPProtocol And m_enmState <> sckClosed Then
284 Err.Raise sckInvalidOp, "CSocketMaster.RemotePort", "Invalid operation at current state"
287 If lngPort <
0 Or lngPort >
65535 Then
288 Err.Raise sckInvalidArg, "CSocketMaster.RemotePort", "The argument passed to a function was not in the correct format or in the specified range."
290 m_lngRemotePort = lngPort
296 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.RemotePort"
301 Public Property Get RemoteHost() As String
303 On Error GoTo RemoteHost_Err
305 RemoteHost = m_strRemoteHost
309 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.RemoteHost"
314 Public Property Let RemoteHost(ByVal strHost As String)
316 On Error GoTo RemoteHost_Err
319 If m_enmProtocol = sckTCPProtocol And m_enmState <> sckClosed Then
320 Err.Raise sckInvalidOp, "CSocketMaster.RemoteHost", "Invalid operation at current state"
323 m_strRemoteHost = strHost
327 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.RemoteHost"
332 Public Property Get RemoteHostIP() As String
334 On Error GoTo RemoteHostIP_Err
336 RemoteHostIP = m_strRemoteHostIP
340 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.RemoteHostIP"
345 Public Property Get LocalPort() As Long
347 On Error GoTo LocalPort_Err
350 If m_lngLocalPortBind =
0 Then
351 LocalPort = m_lngLocalPort
353 LocalPort = m_lngLocalPortBind
359 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.LocalPort"
364 Public Property Let LocalPort(ByVal lngPort As Long)
366 On Error GoTo LocalPort_Err
369 If m_enmState <> sckClosed Then
370 Err.Raise sckInvalidOp, "CSocketMaster.LocalPort", "Invalid operation at current state"
373 If lngPort <
0 Or lngPort >
65535 Then
374 Err.Raise sckInvalidArg, "CSocketMaster.LocalPort", "The argument passed to a function was not in the correct format or in the specified range."
376 m_lngLocalPort = lngPort
382 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.LocalPort"
387 Public Property Get State() As SockState
389 On Error GoTo State_Err
395 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.State"
400 Public Property Get LocalHostName() As String
402 On Error GoTo LocalHostName_Err
404 LocalHostName = GetLocalHostName
408 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.LocalHostName"
413 Public Property Get LocalIP() As String
415 On Error GoTo LocalIP_Err
418 If m_enmState = sckConnected Then
419 LocalIP = m_strLocalIP
427 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.LocalIP"
432 Public Property Get BytesReceived() As Long
434 On Error GoTo BytesReceived_Err
437 If m_enmProtocol = sckTCPProtocol Then
438 BytesReceived = Len(m_strRecvBuffer)
440 BytesReceived = GetBufferLenUDP
446 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.BytesReceived"
451 Public Property Get SocketHandle() As Long
453 On Error GoTo SocketHandle_Err
455 SocketHandle = m_lngSocketHandle
459 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.SocketHandle"
464 Public Property Get Tag() As String
466 On Error GoTo Tag_Err
472 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Tag"
477 Public Property Let Tag(ByVal strTag As String)
479 On Error GoTo Tag_Err
485 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Tag"
490 Public Property Get Protocol() As ProtocolConstants
492 On Error GoTo Protocol_Err
494 Protocol = m_enmProtocol
498 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Protocol"
503 Public Property Let Protocol(ByVal enmProtocol As ProtocolConstants)
505 On Error GoTo Protocol_Err
508 If m_enmState <> sckClosed Then
509 Err.Raise sckInvalidOp, "CSocketMaster.Protocol", "Invalid operation at current state"
511 m_enmProtocol = enmProtocol
517 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Protocol"
522 'Destroys the socket if it exists and unregisters it
524 Private Sub DestroySocket()
526 On Error GoTo DestroySocket_Err
529 If Not m_lngSocketHandle = INVALID_SOCKET Then
530 Dim lngResult As Long
531 lngResult = api_closesocket(m_lngSocketHandle)
533 If lngResult = SOCKET_ERROR Then
534 m_enmState = sckError
535 Dim lngErrorCode As Long
536 lngErrorCode = Err.LastDllError
537 Err.Raise lngErrorCode, "CSocketMaster.DestroySocket", GetErrorDescription(lngErrorCode)
539 modSocketMaster.UnregisterSocket m_lngSocketHandle
540 m_lngSocketHandle = INVALID_SOCKET
547 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.DestroySocket"
552 Public Sub CloseSck()
554 On Error GoTo CloseSck_Err
557 If m_lngSocketHandle = INVALID_SOCKET Then Exit Sub
558 m_enmState = sckClosing
559 CleanResolutionSystem
561 m_lngLocalPortBind =
0
562 m_strRemoteHostIP = ""
565 m_lngSendBufferLen =
0
566 m_lngRecvBufferLen =
0
567 m_enmState = sckClosed
571 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.CloseSck"
576 'Tries to create a socket if there isn't one yet and registers
577 'it to the control list.
578 'Returns TRUE if it has success
579 Private Function SocketExists() As Boolean
581 On Error GoTo SocketExists_Err
584 Dim lngResult As Long
585 Dim lngErrorCode As Long
587 'check if there is a socket already
588 If m_lngSocketHandle = INVALID_SOCKET Then
590 'decide what kind of socket we are creating, TCP or UDP
591 If m_enmProtocol = sckTCPProtocol Then
592 lngResult = api_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
594 lngResult = api_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
597 If lngResult = INVALID_SOCKET Then
598 m_enmState = sckError
600 lngErrorCode = Err.LastDllError
601 Dim blnCancelDisplay As Boolean
602 blnCancelDisplay = True
603 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.SocketExists", "",
0, blnCancelDisplay)
605 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.SocketExists"
607 m_lngSocketHandle = lngResult
608 'set and get some socket options
610 SocketExists = modSocketMaster.RegisterSocket(m_lngSocketHandle, ObjPtr(Me), True)
617 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.SocketExists"
622 'Tries to connect to RemoteHost if it was passed, or uses
623 'm_strRemoteHost instead. If it is a hostname tries to
625 Public Sub Connect(Optional RemoteHost As Variant, _
626 Optional RemotePort As Variant)
628 On Error GoTo Connect_Err
631 If m_enmState <> sckClosed Then
632 Err.Raise sckInvalidOp, "CSocketMaster.Connect", "Invalid operation at current state"
635 If Not IsMissing(RemoteHost) Then
636 m_strRemoteHost = CStr(RemoteHost)
639 'for some reason we get a GPF if we try to
640 'resolve a null string, so we replace it with
642 If m_strRemoteHost = vbNullString Then
646 'check if RemotePort is a number between
1 and
65535
647 If Not IsMissing(RemotePort) Then
648 If IsNumeric(RemotePort) Then
649 If CLng(RemotePort) >
65535 Or CLng(RemotePort) <
1 Then
650 Err.Raise sckInvalidArg, "CSocketMaster.Connect", "The argument passed to a function was not in the correct format or in the specified range."
652 m_lngRemotePort = CLng(RemotePort)
656 Err.Raise sckUnsupported, "CSocketMaster.Connect", "Unsupported variant type."
660 'create a socket if there isn't one yet
661 If Not SocketExists Then Exit Sub
663 'Here we bind the socket
664 If Not BindInternal Then Exit Sub
666 'If we are using UDP we just exit silently.
667 'Remember UDP is a connectionless protocol.
668 If m_enmProtocol = sckUDPProtocol Then
673 'try to get a
32 bits long that is used to identify a host
674 Dim lngAddress As Long
675 lngAddress = ResolveIfHostname(m_strRemoteHost)
677 'We've got two options here:
678 '
1) m_strRemoteHost was an IP, so a resolution wasn't
679 ' necessary, and now lngAddress is a
32 bits long and
680 ' we proceed to connect.
681 '
2) m_strRemoteHost was a hostname, so a resolution was
682 ' necessary and it's taking place right now. We leave
684 If lngAddress <> vbNull Then
685 '
136 registrar "~SOCK: Conectando directamente por IP",
3
686 ConnectToIP lngAddress,
0
692 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Connect"
697 'When the system resolves a hostname in asynchronous way we
698 'call this function to decide what to do with the result.
699 Private Sub PostResolution(ByVal lngAsynHandle As Long, _
700 ByVal lngErrorCode As Long)
701 'erase that record from the collection since we won't need it any longer
703 On Error GoTo PostResolution_Err
705 m_colWaitingResolutions.Remove "R" & lngAsynHandle
706 UnregisterResolution lngAsynHandle
708 If m_enmState <> sckResolvingHost Then Exit Sub
709 If lngErrorCode =
0 Then 'if there weren't errors trying to resolve the hostname
710 m_enmState = sckHostResolved
711 Dim udtHostent As HOSTENT
712 Dim lngPtrToIP As Long
713 Dim arrIpAddress(
1 To
4) As Byte
714 Dim lngRemoteHostAddress As Long
716 Dim strIpAddress As String
717 api_CopyMemory udtHostent, ByVal m_lngMemoryPointer, LenB(udtHostent)
718 api_CopyMemory lngPtrToIP, ByVal udtHostent.hAddrList,
4
719 api_CopyMemory arrIpAddress(
1), ByVal lngPtrToIP,
4
720 api_CopyMemory lngRemoteHostAddress, ByVal lngPtrToIP,
4
721 'free memory, won't need it any longer
724 'We turn the
32 bits long into a readable string.
725 'Note: we don't need this string. I put this here just
726 'in case you need it.
728 strIpAddress = strIpAddress & arrIpAddress(Count) & "."
731 strIpAddress = Left$(strIpAddress, Len(strIpAddress) -
1)
732 ConnectToIP lngRemoteHostAddress,
0
733 Else 'there were errors trying to resolve the hostname
736 ConnectToIP vbNull, lngErrorCode
742 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.PostResolution"
747 'This procedure is called by the WindowProc callback function.
748 'The lngEventID argument is an ID of the network event
749 'occurred for the socket. The lngErrorCode argument contains
750 'an error code only if an error was occurred during an
751 'asynchronous execution.
752 Private Sub PostSocket(ByVal lngEventID As Long, _
753 ByVal lngErrorCode As Long)
755 On Error GoTo PostSocket_Err
757 Dim blnCancelDisplay As Boolean
759 'handle any possible error
760 If lngErrorCode <>
0 Then
761 m_enmState = sckError
762 Registrar "~SOCK: Estado -> sckError",
3
763 blnCancelDisplay = True
764 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.PostSocket", "",
0, blnCancelDisplay)
766 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.PostSocket"
770 Dim udtSockAddr As sockaddr_in
771 Dim lngResult As Long
772 Dim lngBytesReceived As Long
774 Select Case lngEventID
776 '======================================================================
779 'Arrival of this message means that the connection initiated by the call
780 'of the connect Winsock API function was successfully established.
781 'registrar "~SOCK:" & "FD_CONNECT " & m_lngSocketHandle,
3
782 If m_enmState <> sckConnecting Then
783 Registrar "~SOCK:" & "Advertencia: Omitiendo FD_CONNECT",
3
787 'Get the local parameters
788 GetLocalInfo m_lngSocketHandle, m_lngLocalPortBind, m_strLocalIP
789 'Get the connection local end-point parameters
790 GetRemoteInfo m_lngSocketHandle, m_lngRemotePort, m_strRemoteHostIP, m_strRemoteHost
791 m_enmState = sckConnected
792 Registrar "~SOCK: Estado -> sckConnected",
3
795 '======================================================================
798 'This message means that the socket in a write-able
799 'state, that is, buffer for outgoing data of the transport
800 'service is empty and ready to receive data to send through
802 'registrar "~SOCK:" & "FD_WRITE " & m_lngSocketHandle,
3
803 If m_enmState <> sckConnected Then
804 Registrar "~SOCK:" & "Advertencia: Omitiendo FD_WRITE",
3
808 If Len(m_strSendBuffer) >
0 Then
812 '======================================================================
815 'Some data has arrived for this socket.
816 'registrar "~SOCK:" & "FD_READ " & m_lngSocketHandle,
3
817 If m_enmProtocol = sckTCPProtocol Then
818 If m_enmState <> sckConnected Then
819 Registrar "~SOCK:" & "Advertencia: Omitiendo FD_READ",
3
823 'Call the RecvDataToBuffer function that move arrived data
824 'from the Winsock buffer to the local one and returns number
826 lngBytesReceived = RecvDataToBuffer
828 If lngBytesReceived >
0 Then
829 RaiseEvent DataArrival(Len(m_strRecvBuffer))
834 If m_enmState <> sckOpen Then
835 Registrar "~SOCK:" & "Advertencia: Omitiendo FD_READ",
3
839 'If we use UDP we don't remove data from winsock buffer.
840 'We just let the user know the amount received so
841 'he/she can decide what to do.
842 lngBytesReceived = GetBufferLenUDP
844 If lngBytesReceived >
0 Then
845 RaiseEvent DataArrival(lngBytesReceived)
848 'Now the buffer is emptied no matter what the user
849 'dicided to do with the received data
853 '======================================================================
856 'When the socket is in a listening state, arrival of this message
857 'means that a connection request was received. Call the accept
858 'Winsock API function in oreder to create a new socket for the
859 'requested connection.
860 'registrar "~SOCK:" & "FD_ACCEPT " & m_lngSocketHandle,
3
861 If m_enmState <> sckListening Then
862 Registrar "~SOCK:" & "Advertencia: Omitiendo FD_ACCEPT",
3
866 lngResult = api_accept(m_lngSocketHandle, udtSockAddr, LenB(udtSockAddr))
868 If lngResult = INVALID_SOCKET Then
869 lngErrorCode = Err.LastDllError
870 m_enmState = sckError
871 blnCancelDisplay = True
872 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.PostSocket", "",
0, blnCancelDisplay)
874 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.PostSocket"
876 'We assign a temporal instance of CSocketMaster to
877 'handle this new socket until user accepts (or not)
879 modSocketMaster.RegisterAccept lngResult
880 'We change remote info before firing ConnectionRequest
881 'event so the user can see which host is trying to
883 Dim lngTempRP As Long
884 Dim strTempRHIP As String
885 Dim strTempRH As String
886 lngTempRP = m_lngRemotePort
887 strTempRHIP = m_strRemoteHostIP
888 strTempRH = m_strRemoteHost
889 GetRemoteInfo lngResult, m_lngRemotePort, m_strRemoteHostIP, m_strRemoteHost
890 Registrar "~SOCK: Socket aceptado -> " & lngResult,
3
891 RaiseEvent ConnectionRequest(lngResult)
893 'we return original info
894 If m_enmState = sckListening Then
895 m_lngRemotePort = lngTempRP
896 m_strRemoteHostIP = strTempRHIP
897 m_strRemoteHost = strTempRH
900 'This is very important. If the connection wasn't accepted
901 'we must close the socket.
902 If IsAcceptRegistered(lngResult) Then
903 api_closesocket lngResult
904 modSocketMaster.UnregisterSocket lngResult
905 modSocketMaster.UnregisterAccept lngResult
906 Registrar "~SOCK: Socket aceptado cerrado -> " & lngResult,
3
910 '======================================================================
913 'This message means that the remote host is closing the conection
914 'registrar "~SOCK:" & "FD_CLOSE " & m_lngSocketHandle,
3
915 If m_enmState <> sckConnected Then
916 Registrar "~SOCK: Advertencia: Omitiendo FD_CLOSE",
3
920 m_enmState = sckClosing
921 Registrar "~SOCK: Estado -> sckClosing",
3
928 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.PostSocket"
933 'Connect to a given
32 bits long ip
934 Private Sub ConnectToIP(ByVal lngRemoteHostAddress As Long, _
935 ByVal lngErrorCode As Long)
937 On Error GoTo ConnectToIP_Err
939 Dim blnCancelDisplay As Boolean
941 'Check and handle errors
942 If lngErrorCode <>
0 Then
943 m_enmState = sckError
944 blnCancelDisplay = True
945 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.ConnectToIP", "",
0, blnCancelDisplay)
947 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.ConnectToIP"
951 Registrar "~SOCK: Conectando a: " + m_strRemoteHost + " " + m_strRemoteHostIP,
3
952 m_enmState = sckConnecting
953 Registrar "~SOCK: Estado -> sckConnecting",
3
954 Dim udtSockAddr As sockaddr_in
955 Dim lngResult As Long
957 'Build the sockaddr_in structure to pass it to the connect
958 'Winsock API function as an address of the remote host.
960 .sin_addr = lngRemoteHostAddress
961 .sin_family = AF_INET
962 .sin_port = api_htons(modSocketMaster.UnsignedToInteger(m_lngRemotePort))
965 'Call the connect Winsock API function in order to establish connection.
966 lngResult = api_connect(m_lngSocketHandle, udtSockAddr, LenB(udtSockAddr))
968 'Check and handle errors
969 If lngResult = SOCKET_ERROR Then
970 lngErrorCode = Err.LastDllError
972 If lngErrorCode <> WSAEWOULDBLOCK Then
973 If lngErrorCode = WSAEADDRNOTAVAIL Then
974 Err.Raise WSAEADDRNOTAVAIL, "CSocketMaster.ConnectToIP", GetErrorDescription(WSAEADDRNOTAVAIL)
976 m_enmState = sckError
977 blnCancelDisplay = True
978 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.ConnectToIP", "",
0, blnCancelDisplay)
980 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.ConnectToIP"
988 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.ConnectToIP"
992 'Public Sub Bind(Optional LocalPort As Variant, _
993 ' Optional LocalIP As Variant)
995 ' On Error GoTo Bind_Err
998 '
100 If m_enmState <> sckClosed Then
999 '
102 Err.Raise sckInvalidOp, "CSocketMaster.Bind", "Operación invalida en el estado actual"
1002 ''
104 If BindInternal(LocalPort, LocalIP) Then
1004 '
104 If BindInternal(LocalPort, LocalIP) Then
1005 '
106 m_enmState = sckOpen
1013 ' Controlar_Error Erl, Err.Description, "XMR.CSocketMaster.Bind"
1018 'This function binds a socket to a local port and IP.
1019 'Retunrs TRUE if it has success.
1020 Private Function BindInternal(Optional ByVal varLocalPort As Variant, _
1021 Optional ByVal varLocalIP As Variant) As Boolean
1023 On Error GoTo BindInternal_Err
1026 If m_enmState = sckOpen Then
1031 Dim lngLocalPortInternal As Long
1032 Dim strLocalHostInternal As String
1034 Dim lngAddressInternal As Long
1035 Dim lngResult As Long
1036 Dim lngErrorCode As Long
1037 BindInternal = False
1039 'Check if varLocalPort is a number between
0 and
65535
1040 If Not IsMissing(varLocalPort) Then
1041 If IsNumeric(varLocalPort) Then
1042 If varLocalPort <
0 Or varLocalPort >
65535 Then
1043 BindInternal = False
1044 Err.Raise sckInvalidArg, "CSocketMaster.BindInternal", "El argumento pasado a la función no era correcto o no era en el rango especificado"
1046 lngLocalPortInternal = CLng(varLocalPort)
1050 BindInternal = False
1051 Err.Raise sckUnsupported, "CSocketMaster.BindInternal", "Tipos variantes no soportados"
1055 lngLocalPortInternal = m_lngLocalPort
1058 If IsMissing(varLocalIP) Then varLocalIP = "
000.000.000.000"
1059 strLocalHostInternal = CStr(varLocalIP)
1060 'registrar "~SOCK:" & "@Wine => varLocalIP: " & CStr(varLocalIP) & " | strLocalHostInternal: " & CStr(strLocalHostInternal) & " | strIP: " & strIP,
3
1061 'get a
32 bits long IP
1062 lngAddressInternal = ResolveIfHostnameSync(strLocalHostInternal, strIP, lngResult)
1064 'registrar "~SOCK:" & "@Wine => lngResult: " & lngResult,
3
1065 If lngResult <>
0 Then Err.Raise sckInvalidArg, "CSocketMaster.BindInternal", "Argumento inválido"
1067 'create a socket if there isn't one yet
1068 If Not SocketExists Then Exit Function
1069 Dim udtSockAddr As sockaddr_in
1072 .sin_addr = lngAddressInternal
1073 .sin_family = AF_INET
1074 .sin_port = api_htons(modSocketMaster.UnsignedToInteger(lngLocalPortInternal))
1078 lngResult = api_bind(m_lngSocketHandle, udtSockAddr, LenB(udtSockAddr))
1080 If lngResult = SOCKET_ERROR Then
1081 lngErrorCode = Err.LastDllError
1082 Err.Raise lngErrorCode, "CSocketMaster.BindInternal", GetErrorDescription(lngErrorCode)
1085 If lngLocalPortInternal <>
0 Then
1086 '
160 registrar "~SOCK: Servidor enlazado -> " & strLocalHostInternal & " | Puerto -> " & lngLocalPortInternal,
3
1087 m_lngLocalPort = lngLocalPortInternal
1089 lngResult = GetLocalPort(m_lngSocketHandle)
1091 If lngResult = SOCKET_ERROR Then
1092 lngErrorCode = Err.LastDllError
1093 Err.Raise lngErrorCode, "CSocketMaster.BindInternal", GetErrorDescription(lngErrorCode)
1095 'registrar "~SOCK: Servidor enlazado -> " & strLocalHostInternal & " | Puerto -> " & lngLocalPortInternal,
3
1096 m_lngLocalPortBind = lngResult
1106 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.BindInternal"
1111 'Allocate some memory for HOSTEN structure and returns
1112 'a pointer to this buffer if no error occurs.
1113 'Returns
0 if it fails.
1114 Private Function AllocateMemory() As Long
1116 On Error GoTo AllocateMemory_Err
1118 m_lngMemoryHandle = api_GlobalAlloc(GMEM_FIXED, MAXGETHOSTSTRUCT)
1120 If m_lngMemoryHandle <>
0 Then
1121 m_lngMemoryPointer = api_GlobalLock(m_lngMemoryHandle)
1123 If m_lngMemoryPointer <>
0 Then
1124 api_GlobalUnlock (m_lngMemoryHandle)
1125 AllocateMemory = m_lngMemoryPointer
1127 api_GlobalFree (m_lngMemoryHandle)
1128 AllocateMemory = m_lngMemoryPointer '
0
1132 AllocateMemory = m_lngMemoryHandle '
0
1138 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.AllocateMemory"
1143 'Free memory allocated by AllocateMemory
1144 Private Sub FreeMemory()
1146 On Error GoTo FreeMemory_Err
1149 If m_lngMemoryHandle <>
0 Then
1150 m_lngMemoryPointer =
0
1151 api_GlobalFree m_lngMemoryHandle
1152 m_lngMemoryHandle =
0
1153 'registrar "~SOCK: Liberada memoria de resolución",
3
1159 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.FreeMemory"
1164 Private Function GetLocalHostName() As String
1166 On Error GoTo GetLocalHostName_Err
1168 Dim strHostNameBuf As String * LOCAL_HOST_BUFF
1169 Dim lngResult As Long
1170 lngResult = api_gethostname(strHostNameBuf, LOCAL_HOST_BUFF)
1172 If lngResult = SOCKET_ERROR Then
1173 GetLocalHostName = vbNullString
1174 Dim lngErrorCode As Long
1175 lngErrorCode = Err.LastDllError
1176 Err.Raise lngErrorCode, "CSocketMaster.GetLocalHostName", GetErrorDescription(lngErrorCode)
1178 GetLocalHostName = Left$(strHostNameBuf, InStr(
1, strHostNameBuf, vbNullChar) -
1)
1183 GetLocalHostName_Err:
1184 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetLocalHostName"
1189 'Get local IP when the socket isn't connected yet
1190 Private Function GetLocalIP() As String
1192 On Error GoTo GetLocalIP_Err
1194 Dim lngResult As Long
1195 Dim lngPtrToIP As Long
1196 Dim strLocalHost As String
1197 Dim arrIpAddress(
1 To
4) As Byte
1198 Dim Count As Integer
1199 Dim udtHostent As HOSTENT
1200 Dim strIpAddress As String
1201 strLocalHost = GetLocalHostName
1202 lngResult = api_gethostbyname(strLocalHost)
1204 If lngResult =
0 Then
1205 GetLocalIP = vbNullString
1206 Dim lngErrorCode As Long
1207 lngErrorCode = Err.LastDllError
1208 Err.Raise lngErrorCode, "CSocketMaster.GetLocalIP", GetErrorDescription(lngErrorCode)
1210 api_CopyMemory udtHostent, ByVal lngResult, LenB(udtHostent)
1211 api_CopyMemory lngPtrToIP, ByVal udtHostent.hAddrList,
4
1212 api_CopyMemory arrIpAddress(
1), ByVal lngPtrToIP,
4
1215 strIpAddress = strIpAddress & arrIpAddress(Count) & "."
1218 strIpAddress = Left$(strIpAddress, Len(strIpAddress) -
1)
1219 GetLocalIP = strIpAddress
1225 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetLocalIP"
1230 'If Host is an IP doesn't resolve anything and returns a
1232 'If Host isn't an IP then returns vbNull, tries to resolve it
1233 'in asynchronous way.
1234 Private Function ResolveIfHostname(ByVal Host As String) As Long
1236 On Error GoTo ResolveIfHostname_Err
1238 Dim lngAddress As Long
1239 lngAddress = api_inet_addr(Host)
1241 If lngAddress = INADDR_NONE Then 'if Host isn't an IP
1242 ResolveIfHostname = vbNull
1243 m_enmState = sckResolvingHost
1245 If AllocateMemory Then
1246 Dim lngAsynHandle As Long
1247 lngAsynHandle = modSocketMaster.ResolveHost(Host, m_lngMemoryPointer, ObjPtr(Me))
1249 If lngAsynHandle =
0 Then
1251 m_enmState = sckError
1252 Dim lngErrorCode As Long
1253 lngErrorCode = Err.LastDllError
1254 Dim blnCancelDisplay As Boolean
1255 blnCancelDisplay = True
1256 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.ResolveIfHostname", "",
0, blnCancelDisplay)
1258 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.ResolveIfHostname"
1260 m_colWaitingResolutions.Add lngAsynHandle, "R" & lngAsynHandle
1261 Registrar "~SOCK: Resolviendo servidor -> " & Host & " - con control ASYNC: " & lngAsynHandle,
3
1265 m_enmState = sckError
1266 Registrar "~SOCK: Error asignando memoria",
3
1267 Err.Raise sckOutOfMemory, "CSocketMaster.ResolveIfHostname", "Sin memoria"
1270 Else 'if Host is an IP doen't need to resolve anything
1271 ResolveIfHostname = lngAddress
1276 ResolveIfHostname_Err:
1277 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.ResolveIfHostname"
1282 'Resolves a host (if necessary) in synchronous way
1283 'If succeeds returns a
32 bits long IP,
1284 'strHostIP = readable IP string and lngErrorCode =
0
1285 'If fails returns vbNull,
1286 'strHostIP = vbNullString and lngErrorCode <>
0
1287 Private Function ResolveIfHostnameSync(ByVal Host As String, _
1288 ByRef strHostIP As String, _
1289 ByRef lngErrorCode As Long) As Long
1291 On Error GoTo ResolveIfHostnameSync_Err
1293 Dim lngPtrToHOSTENT As Long
1294 Dim udtHostent As HOSTENT
1295 Dim lngAddress As Long
1296 Dim lngPtrToIP As Long
1297 Dim arrIpAddress(
1 To
4) As Byte
1298 Dim Count As Integer
1299 lngAddress = api_inet_addr(Host)
1301 If lngAddress = INADDR_NONE Then 'if Host isn't an IP
1302 lngPtrToHOSTENT = api_gethostbyname(Host)
1304 If lngPtrToHOSTENT =
0 Then
1305 lngErrorCode = Err.LastDllError
1306 strHostIP = vbNullString
1307 ResolveIfHostnameSync = vbNull
1309 api_CopyMemory udtHostent, ByVal lngPtrToHOSTENT, LenB(udtHostent)
1310 api_CopyMemory lngPtrToIP, ByVal udtHostent.hAddrList,
4
1311 api_CopyMemory arrIpAddress(
1), ByVal lngPtrToIP,
4
1312 api_CopyMemory lngAddress, ByVal lngPtrToIP,
4
1315 strHostIP = strHostIP & arrIpAddress(Count) & "."
1318 strHostIP = Left$(strHostIP, Len(strHostIP) -
1)
1320 ResolveIfHostnameSync = lngAddress
1323 Else 'if Host is an IP doen't need to resolve anything
1326 ResolveIfHostnameSync = lngAddress
1331 ResolveIfHostnameSync_Err:
1332 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.ResolveIfHostnameSync"
1337 'Returns local port from a connected or bound socket.
1338 'Returns SOCKET_ERROR if fails.
1339 Private Function GetLocalPort(ByVal lngSocket As Long) As Long
1341 On Error GoTo GetLocalPort_Err
1343 Dim udtSockAddr As sockaddr_in
1344 Dim lngResult As Long
1345 lngResult = api_getsockname(lngSocket, udtSockAddr, LenB(udtSockAddr))
1347 If lngResult = SOCKET_ERROR Then
1348 GetLocalPort = SOCKET_ERROR
1350 GetLocalPort = modSocketMaster.IntegerToUnsigned(api_ntohs(udtSockAddr.sin_port))
1356 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetLocalPort"
1361 Public Sub SendData(data As Variant)
1363 On Error GoTo SendData_Err
1365 Dim arrData() As Byte 'We store the data here before send it
1367 If m_enmProtocol = sckTCPProtocol Then
1368 If m_enmState <> sckConnected Then
1369 Err.Raise sckBadState, "CSocketMaster.SendData", "Wrong protocol or connection state for the requested transaction or request"
1373 Else 'If we use UDP we create a socket if there isn't one yet
1375 If Not SocketExists Then Exit Sub
1376 If Not BindInternal Then Exit Sub
1377 m_enmState = sckOpen
1380 'We need to convert data variant into a byte array
1381 Select Case varType(data)
1384 Dim strdata As String
1385 strdata = CStr(data)
1387 If Len(strdata) =
0 Then Exit Sub
1388 ReDim arrData(Len(strdata) -
1)
1389 arrData() = StrConv(strdata, vbFromUnicode)
1391 Case vbArray + vbByte
1392 Dim strArray As String
1393 strArray = StrConv(data, vbUnicode)
1395 If Len(strArray) =
0 Then Exit Sub
1396 arrData() = StrConv(strArray, vbFromUnicode)
1399 Dim blnData As Boolean
1400 blnData = CBool(data)
1401 ReDim arrData(LenB(blnData) -
1)
1402 api_CopyMemory arrData(
0), blnData, LenB(blnData)
1406 bytData = CByte(data)
1407 ReDim arrData(LenB(bytData) -
1)
1408 api_CopyMemory arrData(
0), bytData, LenB(bytData)
1411 Dim curData As Currency
1412 curData = CCur(data)
1413 ReDim arrData(LenB(curData) -
1)
1414 api_CopyMemory arrData(
0), curData, LenB(curData)
1418 datData = CDate(data)
1419 ReDim arrData(LenB(datData) -
1)
1420 api_CopyMemory arrData(
0), datData, LenB(datData)
1423 Dim dblData As Double
1424 dblData = CDbl(data)
1425 ReDim arrData(LenB(dblData) -
1)
1426 api_CopyMemory arrData(
0), dblData, LenB(dblData)
1429 Dim intData As Integer
1430 intData = CInt(data)
1431 ReDim arrData(LenB(intData) -
1)
1432 api_CopyMemory arrData(
0), intData, LenB(intData)
1436 lngData = CLng(data)
1437 ReDim arrData(LenB(lngData) -
1)
1438 api_CopyMemory arrData(
0), lngData, LenB(lngData)
1441 Dim sngData As Single
1442 sngData = CSng(data)
1443 ReDim arrData(LenB(sngData) -
1)
1444 api_CopyMemory arrData(
0), sngData, LenB(sngData)
1447 Err.Raise sckUnsupported, "CSocketMaster.SendData", "Unsupported variant type."
1450 'if there's already something in the buffer that means we are
1451 'already sending data, so we put the new data in the buffer
1453 If Len(m_strSendBuffer) >
0 Then
1454 m_strSendBuffer = m_strSendBuffer + StrConv(arrData(), vbUnicode)
1457 m_strSendBuffer = m_strSendBuffer + StrConv(arrData(), vbUnicode)
1465 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.SendData"
1470 'Check which protocol we are using to decide which
1471 'function should handle the data sending.
1472 Private Sub SendBufferedData()
1474 On Error GoTo SendBufferedData_Err
1477 If m_enmProtocol = sckTCPProtocol Then
1485 SendBufferedData_Err:
1486 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.SendBufferedData"
1491 'Send buffered data if we are using UDP protocol.
1492 Private Sub SendBufferedDataUDP()
1494 On Error GoTo SendBufferedDataUDP_Err
1496 Dim lngAddress As Long
1497 Dim udtSockAddr As sockaddr_in
1498 Dim arrData() As Byte
1499 Dim lngBufferLength As Long
1500 Dim lngResult As Long
1501 Dim lngErrorCode As Long
1502 Dim strTemp As String
1503 lngAddress = ResolveIfHostnameSync(m_strRemoteHost, strTemp, lngErrorCode)
1505 If lngErrorCode <>
0 Then
1506 m_strSendBuffer = ""
1508 If lngErrorCode = WSAEAFNOSUPPORT Then
1509 Err.Raise lngErrorCode, "CSocketMaster.SendBufferedDataUDP", GetErrorDescription(lngErrorCode)
1511 Err.Raise sckInvalidArg, "CSocketMaster.SendBufferedDataUDP", "Invalid argument"
1516 .sin_addr = lngAddress
1517 .sin_family = AF_INET
1518 .sin_port = api_htons(modSocketMaster.UnsignedToInteger(m_lngRemotePort))
1521 lngBufferLength = Len(m_strSendBuffer)
1522 arrData() = StrConv(m_strSendBuffer, vbFromUnicode)
1523 m_strSendBuffer = ""
1524 lngResult = api_sendto(m_lngSocketHandle, arrData(
0), lngBufferLength,
0&, udtSockAddr, LenB(udtSockAddr))
1526 If lngResult = SOCKET_ERROR Then
1527 lngErrorCode = Err.LastDllError
1528 m_enmState = sckError
1529 Dim blnCancelDisplay As Boolean
1530 blnCancelDisplay = True
1531 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.SendBufferedDataUDP", "",
0, blnCancelDisplay)
1533 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.SendBufferedDataUDP"
1538 SendBufferedDataUDP_Err:
1539 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.SendBufferedDataUDP"
1544 'Send buffered data if we are using TCP protocol.
1545 Private Sub SendBufferedDataTCP()
1547 On Error GoTo SendBufferedDataTCP_Err
1549 Dim arrData() As Byte
1550 Dim lngBufferLength As Long
1551 Dim lngResult As Long
1552 Dim lngTotalSent As Long
1554 Do Until lngResult = SOCKET_ERROR Or Len(m_strSendBuffer) =
0
1555 lngBufferLength = Len(m_strSendBuffer)
1557 If lngBufferLength > m_lngSendBufferLen Then
1558 lngBufferLength = m_lngSendBufferLen
1559 arrData() = StrConv(Left$(m_strSendBuffer, m_lngSendBufferLen), vbFromUnicode)
1561 arrData() = StrConv(m_strSendBuffer, vbFromUnicode)
1564 lngResult = api_send(m_lngSocketHandle, arrData(
0), lngBufferLength,
0&)
1566 If lngResult = SOCKET_ERROR Then
1567 Dim lngErrorCode As Long
1568 lngErrorCode = Err.LastDllError
1570 If lngErrorCode = WSAEWOULDBLOCK Then
1571 Registrar "~SOCK:" & "Advertencia: Buffer de envío lleno, esperando...",
3
1573 If lngTotalSent >
0 Then RaiseEvent SendProgress(lngTotalSent, Len(m_strSendBuffer))
1575 m_enmState = sckError
1576 Dim blnCancelDisplay As Boolean
1577 blnCancelDisplay = True
1578 RaiseEvent error(lngErrorCode, GetErrorDescription(lngErrorCode),
0, "CSocketMaster.SendBufferedData", "",
0, blnCancelDisplay)
1580 If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.SendBufferedData"
1584 Registrar "~SOCK: Bytes enviados => " & lngResult,
3
1585 lngTotalSent = lngTotalSent + lngResult
1587 If Len(m_strSendBuffer) > lngResult Then
1588 m_strSendBuffer = Mid$(m_strSendBuffer, lngResult +
1)
1590 Registrar "~SOCK: Envío terminado",
3
1591 m_strSendBuffer = ""
1593 lngTemp = lngTotalSent
1595 RaiseEvent SendProgress(lngTemp,
0)
1596 RaiseEvent SendComplete
1604 SendBufferedDataTCP_Err:
1605 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.SendBufferedDataTCP"
1610 'This function retrieves data from the Winsock buffer
1611 'into the class local buffer. The function returns number
1612 'of bytes retrieved (received).
1613 Private Function RecvDataToBuffer() As Long
1615 On Error GoTo RecvDataToBuffer_Err
1617 Dim arrBuffer() As Byte
1618 Dim lngBytesReceived As Long
1619 Dim strBuffTemporal As String
1620 ReDim arrBuffer(m_lngRecvBufferLen -
1)
1621 lngBytesReceived = api_recv(m_lngSocketHandle, arrBuffer(
0), m_lngRecvBufferLen,
0&)
1623 If lngBytesReceived = SOCKET_ERROR Then
1624 m_enmState = sckError
1625 Dim lngErrorCode As Long
1626 lngErrorCode = Err.LastDllError
1627 Err.Raise lngErrorCode, "CSocketMaster.RecvDataToBuffer", GetErrorDescription(lngErrorCode)
1628 ElseIf lngBytesReceived >
0 Then
1629 strBuffTemporal = StrConv(arrBuffer(), vbUnicode)
1630 m_strRecvBuffer = m_strRecvBuffer & Left$(strBuffTemporal, lngBytesReceived)
1631 RecvDataToBuffer = lngBytesReceived
1636 RecvDataToBuffer_Err:
1637 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.RecvDataToBuffer"
1642 'Retrieves some socket options.
1643 'If it is an UDP socket also sets SO_BROADCAST option.
1644 Private Sub ProcessOptions()
1646 On Error GoTo ProcessOptions_Err
1648 Dim lngResult As Long
1649 Dim lngBuffer As Long
1650 Dim lngErrorCode As Long
1652 If m_enmProtocol = sckTCPProtocol Then
1653 lngResult = api_getsockopt(m_lngSocketHandle, SOL_SOCKET, SO_RCVBUF, lngBuffer, LenB(lngBuffer))
1655 If lngResult = SOCKET_ERROR Then
1656 lngErrorCode = Err.LastDllError
1657 Err.Raise lngErrorCode, "CSocketMaster.ProcessOptions", GetErrorDescription(lngErrorCode)
1659 m_lngRecvBufferLen = lngBuffer
1662 lngResult = api_getsockopt(m_lngSocketHandle, SOL_SOCKET, SO_SNDBUF, lngBuffer, LenB(lngBuffer))
1664 If lngResult = SOCKET_ERROR Then
1665 lngErrorCode = Err.LastDllError
1666 Err.Raise lngErrorCode, "CSocketMaster.ProcessOptions", GetErrorDescription(lngErrorCode)
1668 m_lngSendBufferLen = lngBuffer
1673 lngResult = api_setsockopt(m_lngSocketHandle, SOL_SOCKET, SO_BROADCAST, lngBuffer, LenB(lngBuffer))
1674 lngResult = api_getsockopt(m_lngSocketHandle, SOL_SOCKET, SO_MAX_MSG_SIZE, lngBuffer, LenB(lngBuffer))
1676 If lngResult = SOCKET_ERROR Then
1677 lngErrorCode = Err.LastDllError
1678 Err.Raise lngErrorCode, "CSocketMaster.ProcessOptions", GetErrorDescription(lngErrorCode)
1680 m_lngRecvBufferLen = lngBuffer
1681 m_lngSendBufferLen = lngBuffer
1685 'registrar "~SOCK:" & "Tamaño de buffer para envíar: " & m_lngRecvBufferLen,
3
1686 'registrar "~SOCK:" & "Tamaño de buffer para recibir: " & m_lngSendBufferLen,
3
1690 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.ProcessOptions"
1695 Public Sub GetData(ByRef data As Variant, _
1696 Optional varType As Variant, _
1697 Optional maxLen As Variant)
1699 On Error GoTo GetData_Err
1702 If m_enmProtocol = sckTCPProtocol Then
1703 If m_enmState <> sckConnected And Not m_blnAcceptClass Then
1704 Err.Raise sckBadState, "CSocketMaster.GetData", "Wrong protocol or connection state for the requested transaction or request"
1710 If m_enmState <> sckOpen Then
1711 Err.Raise sckBadState, "CSocketMaster.GetData", "Wrong protocol or connection state for the requested transaction or request"
1715 If GetBufferLenUDP =
0 Then Exit Sub
1718 If Not IsMissing(maxLen) Then
1719 If IsNumeric(maxLen) Then
1720 If CLng(maxLen) <
0 Then
1721 Err.Raise sckInvalidArg, "CSocketMaster.GetData", "The argument passed to a function was not in the correct format or in the specified range."
1726 If m_enmProtocol = sckTCPProtocol Then
1727 maxLen = Len(m_strRecvBuffer)
1729 maxLen = GetBufferLenUDP
1734 Dim lngBytesRecibidos As Long
1735 lngBytesRecibidos = RecvData(data, False, varType, maxLen)
1736 Registrar "~SOCK: Bytes Obtenidos del buffer: " & lngBytesRecibidos,
3
1740 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetData"
1745 Public Sub PeekData(ByRef data As Variant, _
1746 Optional varType As Variant, _
1747 Optional maxLen As Variant)
1749 On Error GoTo PeekData_Err
1752 If m_enmProtocol = sckTCPProtocol Then
1753 If m_enmState <> sckConnected Then
1754 Err.Raise sckBadState, "CSocketMaster.PeekData", "Wrong protocol or connection state for the requested transaction or request"
1760 If m_enmState <> sckOpen Then
1761 Err.Raise sckBadState, "CSocketMaster.PeekData", "Wrong protocol or connection state for the requested transaction or request"
1765 If GetBufferLenUDP =
0 Then Exit Sub
1768 If Not IsMissing(maxLen) Then
1769 If IsNumeric(maxLen) Then
1770 If CLng(maxLen) <
0 Then
1771 Err.Raise sckInvalidArg, "CSocketMaster.PeekData", "The argument passed to a function was not in the correct format or in the specified range."
1776 If m_enmProtocol = sckTCPProtocol Then
1777 maxLen = Len(m_strRecvBuffer)
1779 maxLen = GetBufferLenUDP
1784 Dim lngBytesRecibidos As Long
1785 lngBytesRecibidos = RecvData(data, True, varType, maxLen)
1786 Registrar "~SOCK: Bytes obtenidos del buffer: " & lngBytesRecibidos,
3
1790 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.PeekData"
1795 'This function is to retrieve data from the buffer. If we are using TCP
1796 'then the data is retrieved from a local buffer (m_strRecvBuffer). If we
1797 'are using UDP the data is retrieved from winsock buffer.
1798 'It can be called by two public methods of the class - GetData and PeekData.
1799 'Behavior of the function is defined by the blnPeek argument. If a value of
1800 'that argument is TRUE, the function returns number of bytes in the
1801 'buffer, and copy data from that buffer into the data argument.
1802 'If a value of the blnPeek is FALSE, then this function returns number of
1803 'bytes received, and move data from the buffer into the data
1804 'argument. MOVE means that data will be removed from the buffer.
1805 Private Function RecvData(ByRef data As Variant, _
1806 ByVal blnPeek As Boolean, _
1807 Optional varClass As Variant, _
1808 Optional maxLen As Variant) As Long
1810 On Error GoTo RecvData_Err
1812 Dim blnMaxLenMiss As Boolean
1813 Dim blnClassMiss As Boolean
1814 'Dim strRecvData As String
1815 Dim lngBufferLen As Long
1816 Dim arrBuffer() As Byte
1817 Dim lngErrorCode As Long
1819 If m_enmProtocol = sckTCPProtocol Then
1820 lngBufferLen = Len(m_strRecvBuffer)
1822 lngBufferLen = GetBufferLenUDP
1825 blnMaxLenMiss = IsMissing(maxLen)
1826 blnClassMiss = IsMissing(varClass)
1828 'Select type of data
1829 If varType(data) = vbEmpty Then
1830 If blnClassMiss Then varClass = vbArray + vbByte
1832 varClass = varType(data)
1835 'As stated on Winsock control documentation if the
1836 'data type passed is string or byte array type then
1837 'we must take into account maxLen argument.
1838 'If it is another type maxLen is ignored.
1839 If varClass = vbString Or varClass = vbArray + vbByte Then
1840 If blnMaxLenMiss Then 'if maxLen argument is missing
1841 If lngBufferLen =
0 Then
1843 arrBuffer = StrConv("", vbFromUnicode)
1847 RecvData = lngBufferLen
1848 BuildArray lngBufferLen, blnPeek, lngErrorCode, arrBuffer
1851 Else 'if maxLen argument is not missing
1853 If maxLen =
0 Or lngBufferLen =
0 Then
1855 arrBuffer = StrConv("", vbFromUnicode)
1858 If m_enmProtocol = sckUDPProtocol Then
1860 Err.Raise WSAEMSGSIZE, "CSocketMaster.RecvData", GetErrorDescription(WSAEMSGSIZE)
1864 ElseIf maxLen > lngBufferLen Then
1865 RecvData = lngBufferLen
1866 BuildArray lngBufferLen, blnPeek, lngErrorCode, arrBuffer
1868 RecvData = CLng(maxLen)
1869 BuildArray CLng(maxLen), blnPeek, lngErrorCode, arrBuffer
1874 Select Case varClass
1877 Dim strdata As String
1878 strdata = StrConv(arrBuffer(), vbUnicode)
1881 Case vbArray + vbByte
1885 Dim blnData As Boolean
1887 If LenB(blnData) > lngBufferLen Then Exit Function
1888 BuildArray LenB(blnData), blnPeek, lngErrorCode, arrBuffer
1889 RecvData = LenB(blnData)
1890 api_CopyMemory blnData, arrBuffer(
0), LenB(blnData)
1896 If LenB(bytData) > lngBufferLen Then Exit Function
1897 BuildArray LenB(bytData), blnPeek, lngErrorCode, arrBuffer
1898 RecvData = LenB(bytData)
1899 api_CopyMemory bytData, arrBuffer(
0), LenB(bytData)
1903 Dim curData As Currency
1905 If LenB(curData) > lngBufferLen Then Exit Function
1906 BuildArray LenB(curData), blnPeek, lngErrorCode, arrBuffer
1907 RecvData = LenB(curData)
1908 api_CopyMemory curData, arrBuffer(
0), LenB(curData)
1914 If LenB(datData) > lngBufferLen Then Exit Function
1915 BuildArray LenB(datData), blnPeek, lngErrorCode, arrBuffer
1916 RecvData = LenB(datData)
1917 api_CopyMemory datData, arrBuffer(
0), LenB(datData)
1921 Dim dblData As Double
1923 If LenB(dblData) > lngBufferLen Then Exit Function
1924 BuildArray LenB(dblData), blnPeek, lngErrorCode, arrBuffer
1925 RecvData = LenB(dblData)
1926 api_CopyMemory dblData, arrBuffer(
0), LenB(dblData)
1930 Dim intData As Integer
1932 If LenB(intData) > lngBufferLen Then Exit Function
1933 BuildArray LenB(intData), blnPeek, lngErrorCode, arrBuffer
1934 RecvData = LenB(intData)
1935 api_CopyMemory intData, arrBuffer(
0), LenB(intData)
1941 If LenB(lngData) > lngBufferLen Then Exit Function
1942 BuildArray LenB(lngData), blnPeek, lngErrorCode, arrBuffer
1943 RecvData = LenB(lngData)
1944 api_CopyMemory lngData, arrBuffer(
0), LenB(lngData)
1948 Dim sngData As Single
1950 If LenB(sngData) > lngBufferLen Then Exit Function
1951 BuildArray LenB(sngData), blnPeek, lngErrorCode, arrBuffer
1952 RecvData = LenB(sngData)
1953 api_CopyMemory sngData, arrBuffer(
0), LenB(sngData)
1957 Err.Raise sckUnsupported, "CSocketMaster.RecvData", "Unsupported variant type."
1960 'if BuildArray returns an error is handled here
1961 If lngErrorCode <>
0 Then
1962 Err.Raise lngErrorCode, "CSocketMaster.RecvData", GetErrorDescription(lngErrorCode)
1968 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.RecvData"
1973 'Returns a byte array of Size bytes filled with incoming buffer data.
1974 Private Sub BuildArray(ByVal Size As Long, _
1975 ByVal blnPeek As Boolean, _
1976 ByRef lngErrorCode As Long, _
1977 ByRef bytArray() As Byte)
1979 On Error GoTo BuildArray_Err
1981 Dim strdata As String
1983 If m_enmProtocol = sckTCPProtocol Then
1984 strdata = Left$(m_strRecvBuffer, CLng(Size))
1986 If strdata <> vbNullString Then bytArray = StrConv(strdata, vbFromUnicode)
1987 If Not blnPeek Then m_strRecvBuffer = Mid$(m_strRecvBuffer, Size +
1)
1989 Dim arrBuffer() As Byte
1990 Dim lngResult As Long
1991 Dim udtSockAddr As sockaddr_in
1992 Dim lngFlags As Long
1994 If blnPeek Then lngFlags = MSG_PEEK
1995 ReDim arrBuffer(Size -
1)
1996 lngResult = api_recvfrom(m_lngSocketHandle, arrBuffer(
0), Size, lngFlags, udtSockAddr, LenB(udtSockAddr))
1998 If lngResult = SOCKET_ERROR Then
1999 lngErrorCode = Err.LastDllError
2002 bytArray = arrBuffer
2003 GetRemoteInfoFromSI udtSockAddr, m_lngRemotePort, m_strRemoteHostIP, m_strRemoteHost
2009 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.BuildArray"
2014 'Clean resolution system that is in charge of
2015 'asynchronous hostname resolutions.
2016 Private Sub CleanResolutionSystem()
2018 On Error GoTo CleanResolutionSystem_Err
2020 Dim varAsynHandle As Variant
2021 Dim lngResult As Long
2023 'cancel async resolutions if they're still running
2024 For Each varAsynHandle In m_colWaitingResolutions
2025 lngResult = api_WSACancelAsyncRequest(varAsynHandle)
2027 If lngResult =
0 Then
2028 modSocketMaster.UnregisterResolution varAsynHandle
2029 Set m_colWaitingResolutions = Nothing
2030 Set m_colWaitingResolutions = New Collection
2031 'free memory buffer where resolution results are stored
2039 CleanResolutionSystem_Err:
2040 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.CleanResolutionSystem"
2047 On Error GoTo Listen_Err
2050 If m_enmState <> sckClosed And m_enmState <> sckOpen Then
2051 Err.Raise sckInvalidOp, "CSocketMaster.Listen", "Invalid operation at current state"
2054 If Not SocketExists Then Exit Sub
2055 If Not BindInternal Then Exit Sub
2056 Dim lngResult As Long
2057 lngResult = api_listen(m_lngSocketHandle, SOMAXCONN)
2059 If lngResult = SOCKET_ERROR Then
2060 Dim lngErrorCode As Long
2061 lngErrorCode = Err.LastDllError
2062 Err.Raise lngErrorCode, "CSocketMaster.Listen", GetErrorDescription(lngErrorCode)
2064 m_enmState = sckListening
2065 Registrar "~SOCK: Estado -> sckListening ",
3
2071 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Listen"
2076 Public Sub Accept(requestID As Long)
2078 On Error GoTo Accept_Err
2081 If m_enmState <> sckClosed Then
2082 Registrar "~SOCK: Operación inválida en el estado actual",
3
2085 m_lngSocketHandle = requestID
2086 m_enmProtocol = sckTCPProtocol
2089 If Not modSocketMaster.IsAcceptRegistered(requestID) Then
2090 If IsSocketRegistered(requestID) Then
2091 m_lngSocketHandle = INVALID_SOCKET
2092 m_lngRecvBufferLen =
0
2093 m_lngSendBufferLen =
0
2094 Registrar "~SOCK: Protocolo incorrecto o estado de conexión para la transacción",
3
2096 m_blnAcceptClass = True
2097 m_enmState = sckConnected
2098 Registrar "~SOCK: Estado -> sckConnected",
3
2099 GetLocalInfo m_lngSocketHandle, m_lngLocalPortBind, m_strLocalIP
2100 modSocketMaster.RegisterSocket m_lngSocketHandle, ObjPtr(Me), False
2105 Dim clsSocket As CSocketMaster
2106 Set clsSocket = GetAcceptClass(requestID)
2107 modSocketMaster.UnregisterAccept requestID
2108 GetLocalInfo m_lngSocketHandle, m_lngLocalPortBind, m_strLocalIP
2109 GetRemoteInfo m_lngSocketHandle, m_lngRemotePort, m_strRemoteHostIP, m_strRemoteHost
2110 m_enmState = sckConnected
2111 Registrar "~SOCK: Estado -> sckConnected",
3
2113 If clsSocket.BytesReceived >
0 Then
2114 clsSocket.GetData m_strRecvBuffer
2117 modSocketMaster.Subclass_ChangeOwner requestID, ObjPtr(Me)
2119 If Len(m_strRecvBuffer) >
0 Then RaiseEvent DataArrival(Len(m_strRecvBuffer))
2120 If clsSocket.State = sckClosing Then
2121 m_enmState = sckClosing
2122 Registrar "~SOCK: Estado -> sckClosing",
3
2126 Set clsSocket = Nothing
2130 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.Accept"
2135 'Retrieves local info from a connected socket.
2136 'If succeeds returns TRUE and loads the arguments.
2137 'If fails returns FALSE and arguments are not loaded.
2138 Private Function GetLocalInfo(ByVal lngSocket As Long, _
2139 ByRef lngLocalPort As Long, _
2140 ByRef strLocalIP As String) As Boolean
2142 On Error GoTo GetLocalInfo_Err
2144 GetLocalInfo = False
2145 Dim lngResult As Long
2146 Dim udtSockAddr As sockaddr_in
2147 lngResult = api_getsockname(lngSocket, udtSockAddr, LenB(udtSockAddr))
2149 If lngResult = SOCKET_ERROR Then
2154 lngLocalPort = IntegerToUnsigned(api_ntohs(udtSockAddr.sin_port))
2155 strLocalIP = StringFromPointer(api_inet_ntoa(udtSockAddr.sin_addr))
2161 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetLocalInfo"
2166 'Retrieves remote info from a connected socket.
2167 'If succeeds returns TRUE and loads the arguments.
2168 'If fails returns FALSE and arguments are not loaded.
2169 Private Function GetRemoteInfo(ByVal lngSocket As Long, _
2170 ByRef lngRemotePort As Long, _
2171 ByRef strRemoteHostIP As String, _
2172 ByRef strRemoteHost As String) As Boolean
2174 On Error GoTo GetRemoteInfo_Err
2176 GetRemoteInfo = False
2177 Dim lngResult As Long
2178 Dim udtSockAddr As sockaddr_in
2179 lngResult = api_getpeername(lngSocket, udtSockAddr, LenB(udtSockAddr))
2181 If lngResult =
0 Then
2182 GetRemoteInfo = True
2183 GetRemoteInfoFromSI udtSockAddr, lngRemotePort, strRemoteHostIP, strRemoteHost
2186 strRemoteHostIP = ""
2193 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetRemoteInfo"
2198 'Gets remote info from a sockaddr_in structure.
2199 Private Sub GetRemoteInfoFromSI(ByRef udtSockAddr As sockaddr_in, _
2200 ByRef lngRemotePort As Long, _
2201 ByRef strRemoteHostIP As String, _
2202 ByRef strRemoteHost As String)
2203 'Dim lngResult As Long
2204 'Dim udtHostent As HOSTENT
2206 On Error GoTo GetRemoteInfoFromSI_Err
2208 lngRemotePort = IntegerToUnsigned(api_ntohs(udtSockAddr.sin_port))
2209 strRemoteHostIP = StringFromPointer(api_inet_ntoa(udtSockAddr.sin_addr))
2210 'lngResult = api_gethostbyaddr(udtSockAddr.sin_addr,
4&, AF_INET)
2211 'If lngResult <>
0 Then
2212 ' api_CopyMemory udtHostent, ByVal lngResult, LenB(udtHostent)
2213 ' strRemoteHost = StringFromPointer(udtHostent.hName)
2219 GetRemoteInfoFromSI_Err:
2220 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetRemoteInfoFromSI"
2225 'Returns winsock incoming buffer length from an UDP socket.
2226 Private Function GetBufferLenUDP() As Long
2228 On Error GoTo GetBufferLenUDP_Err
2230 Dim lngResult As Long
2231 Dim lngBuffer As Long
2232 lngResult = api_ioctlsocket(m_lngSocketHandle, FIONREAD, lngBuffer)
2234 If lngResult = SOCKET_ERROR Then
2237 GetBufferLenUDP = lngBuffer
2242 GetBufferLenUDP_Err:
2243 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.GetBufferLenUDP"
2248 'Empty winsock incoming buffer from an UDP socket.
2249 Private Sub EmptyBuffer()
2251 On Error GoTo EmptyBuffer_Err
2254 api_recv m_lngSocketHandle, B, Len(B),
0&
2258 Controlar_Error Erl, Err.Description, "Reseter.CSocketMaster.EmptyBuffer"