-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCSocket.cls
More file actions
1736 lines (1696 loc) · 65.3 KB
/
CSocket.cls
File metadata and controls
1736 lines (1696 loc) · 65.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "CSocket"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
'********************************************************************************
'CSocket class
'Copyright © 2002 by Oleg Gdalevich
'Visual Basic Internet Programming website (http://www.vbip.com)
'********************************************************************************
'To use this class module you need:
' MSocketSupport code module
'********************************************************************************
'Version: 1.0.12 Modified: 17-OCT-2002
'********************************************************************************
'To get latest version of this code please visit the following web page:
'http://www.vbip.com/winsock-api/csocket-class/csocket-class-01.asp
'********************************************************************************
Option Explicit
'
'Added: 23-AUG-2002
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'
'The CSocket protocol's constants as for
'the MS Winsock Control interface
Public Enum ProtocolConstants
sckTCPProtocol = 0
sckUDPProtocol = 1
End Enum
'
'The CSocket error's constants as for
'the MS Winsock Control interface
Public Enum ErrorConstants
sckAddressInUse = 10048
sckAddressNotAvailable = 10049
sckAlreadyComplete = 10037
sckAlreadyConnected = 10056
sckBadState = 40006
sckConnectAborted = 10053
sckConnectionRefused = 10061
sckConnectionReset = 10054
sckGetNotSupported = 394
sckHostNotFound = 11001
sckHostNotFoundTryAgain = 11002
sckInProgress = 10036
sckInvalidArg = 40014
sckInvalidArgument = 10014
sckInvalidOp = 40020
sckInvalidPropertyValue = 380
sckMsgTooBig = 10040
sckNetReset = 10052
sckNetworkSubsystemFailed = 10050
sckNetworkUnreachable = 10051
sckNoBufferSpace = 10055
sckNoData = 11004
sckNonRecoverableError = 11003
sckNotConnected = 10057
sckNotInitialized = 10093
sckNotSocket = 10038
sckOpCanceled = 10004
sckOutOfMemory = 7
sckOutOfRange = 40021
sckPortNotSupported = 10043
sckSetNotSupported = 383
sckSocketShutdown = 10058
sckSuccess = 40017
sckTimedout = 10060
sckUnsupported = 40018
sckWouldBlock = 10035
sckWrongProtocol = 40026
End Enum
'
'The CSocket state's constants as for
'the MS Winsock Control interface
Public Enum StateConstants
sckClosed = 0
sckOpen
sckListening
sckConnectionPending
sckResolvingHost
sckHostResolved
sckConnecting
sckConnected
sckClosing
sckError
End Enum
'
'In order to resolve a host name the MSocketSupport.ResolveHost
'function can be called from the Connect and SendData methods
'of this class. The callback acceptor for that routine is the
'PostGetHostEvent procedure. This procedure determines what to
'do next with the received host's address checking a value of
'the m_varInternalState variable.
Private Enum InternalStateConstants
istConnecting
istSendingDatagram
End Enum
'
Private m_varInternalState As InternalStateConstants
'
'Local (module level) variables to hold values of the
'properties of this (CSocket) class.
Private mvarProtocol As ProtocolConstants
Private mvarState As StateConstants
Private m_lngBytesReceived As Long
Private m_strLocalHostName As String
Private m_strLocalIP As String
Private m_lngLocalPort As Long
Private m_strRemoteHost As String
Private m_strRemoteHostIP As String
Private m_lngRemotePort As Long
Private m_lngSocketHandle As Long
'
'Resolving host names is performed in an asynchronous mode,
'the m_lngRequestID variable just holds the value returned
'by the ResolveHost function from the MSocketSupport module.
Private m_lngRequestID As Long
'
'Internal (for this class) buffers. They are the VB Strings.
'Don't trust that guy who told that the VB String data type
'cannot properly deal with binary data. Actually, it can, and
'moreover you have a lot of means to deal with that data -
'the VB string functions (such as Left, Mid, InStr and so on).
'If you need to get a byte array from a string, just call the
'StrConv function:
'
'byteArray() = StrConv(strBuffer, vbFromUnicode)
'
Private m_strSendBuffer As String 'The internal buffer for outgoing data
Private m_strRecvBuffer As String 'The internal buffer for incoming data
'
'Lenght of the Winsock buffers. By default = 8192 bytes for TCP sockets.
'These values are initialized in the SocketExists function.
'Now, I really don't know why I was in need to get these values.
Private m_lngSendBufferLen As Long
Private m_lngRecvBufferLen As Long
'
'Maximum size of a datagram that can be sent through
'a message-oriented (UDP) socket. This value is returned
'by the InitWinsock function from the MSocketSupport module.
Private m_lngMaxMsgSize As Long
'
'This flag variable indicates that the socket is bound to
'some local socket address
Private m_blnSocketIsBound As Boolean 'Added: 10-MAR-2002
'
Private m_blnSendFlag As Boolean 'Added: 12-SEP-2002
'
'This flag variable indicates that the SO_BROADCAST option
'is set on the socket
Private m_blnBroadcast As Boolean 'Added: 09-JULY-2002
'
'These are those MS Winsock's events.
'Pay attention that the "On" prefix is added.
Public Event OnClose()
Attribute OnClose.VB_Description = "Occurs when the connection has been closed"
Public Event OnConnect()
Attribute OnConnect.VB_Description = "Occurs connect operation is completed"
Public Event OnConnectionRequest(ByVal requestID As Long)
Public Event OnDataArrival(ByVal bytesTotal As Long)
Public Event OnError(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)
Public Event OnSendComplete()
Public Event OnSendProgress(ByVal bytesSent As Long, ByVal bytesRemaining As Long)
Public Sub SendData(varData As Variant)
Attribute SendData.VB_Description = "Send data to remote computer"
'
'data to send - will be built from the varData argument
Dim arrData() As Byte
'value returned by the send(sendto) Winsock API function
Dim lngRetValue As Long
'length of the data to send - needed to call the send(sendto) Winsock API function
Dim lngBufferLength As Long
'this strucure just contains address of the remote socket to send data to;
'only for UDP sockets when the sendto Winsock API function is used
Dim udtSockAddr As sockaddr_in
'
On Error GoTo SendData_Err_Handler
'
'If a connection-oriented (TCP) socket was not created or connected to the
'remote host before calling the SendData method, the MS Winsock Control
'raises the sckBadState error.
If mvarProtocol = sckTCPProtocol Then
'
If m_lngSocketHandle = INVALID_SOCKET Then
Err.Raise sckBadState, "CSocket.SendData", _
"Wrong protocol or connection state for the requested transaction or request."
Exit Sub
End If
'
Else
'
'If the socket is a message-oriented one (UDP), this is OK to create
'it with the call of the SendData method. The SocketExists function
'creates a new socket.
If Not SocketExists Then Exit Sub
'
End If
'
Select Case varType(varData)
Case vbArray + vbByte
'Modified 28-MAY-2002. Thanks to Michael Freidgeim
'--------------------------------
'Dim strArray As String
'strArray = CStr(varData)
arrData() = varData
'--------------------------------
Case vbBoolean
Dim blnData As Boolean
blnData = CBool(varData)
ReDim arrData(LenB(blnData) - 1)
CopyMemory arrData(0), blnData, LenB(blnData)
Case vbByte
Dim bytData As Byte
bytData = CByte(varData)
ReDim arrData(LenB(bytData) - 1)
CopyMemory arrData(0), bytData, LenB(bytData)
Case vbCurrency
Dim curData As Currency
curData = CCur(varData)
ReDim arrData(LenB(curData) - 1)
CopyMemory arrData(0), curData, LenB(curData)
Case vbDate
Dim datData As Date
datData = CDate(varData)
ReDim arrData(LenB(datData) - 1)
CopyMemory arrData(0), datData, LenB(datData)
Case vbDouble
Dim dblData As Double
dblData = CDbl(varData)
ReDim arrData(LenB(dblData) - 1)
CopyMemory arrData(0), dblData, LenB(dblData)
Case vbInteger
Dim intData As Integer
intData = CInt(varData)
ReDim arrData(LenB(intData) - 1)
CopyMemory arrData(0), intData, LenB(intData)
Case vbLong
Dim lngData As Long
lngData = CLng(varData)
ReDim arrData(LenB(lngData) - 1)
CopyMemory arrData(0), lngData, LenB(lngData)
Case vbSingle
Dim sngData As Single
sngData = CSng(varData)
ReDim arrData(LenB(sngData) - 1)
CopyMemory arrData(0), sngData, LenB(sngData)
Case vbString
Dim strData As String
strData = CStr(varData)
ReDim arrData(Len(strData) - 1)
arrData() = StrConv(strData, vbFromUnicode)
Case Else
'
'Unknown data type
'
End Select
'
'Store all the data to send in the module level
'variable m_strSendBuffer.
m_strSendBuffer = StrConv(arrData(), vbUnicode)
'
'Call the SendBufferedData subroutine in order to send the data.
'The SendBufferedData sub is just a common procedure that is
'called from different places in this class.
'Nothing special - just the code reuse.
m_blnSendFlag = True
Call SendBufferedData
'
EXIT_LABEL:
'
Exit Sub
'
SendData_Err_Handler:
'
If Err.LastDllError = WSAENOTSOCK Then
Err.Raise sckBadState, "CSocket.SendData", "Wrong protocol or connection state for the requested transaction or request."
Else
Err.Raise Err.Number, "CSocket.SendData", Err.Description
End If
'
GoTo EXIT_LABEL
'
End Sub
Public Sub PeekData(varData As Variant, Optional varType As Variant, Optional maxLen As Variant)
Attribute PeekData.VB_Description = "Look at incoming data without removing it from the buffer"
'
Dim lngBytesReceived As Long 'value returned by the RecvData function
'
On Error GoTo PeekData_Err_Handler
'
'The RecvData is a universal subroutine that can either to retrieve or peek
'data from the Winsock buffer. If a value of the second argument (blnPeek As Boolean)
'of the RecvData subroutine is True, it will be just peeking.
lngBytesReceived = RecvData(varData, True, IIf(IsMissing(varType), Empty, varType), _
IIf(IsMissing(maxLen), Empty, maxLen))
'
EXIT_LABEL:
'
Exit Sub
'
PeekData_Err_Handler:
'
Err.Raise Err.Number, "CSocket.PeekData", Err.Description
'
GoTo EXIT_LABEL
'
End Sub
Public Sub Listen()
Attribute Listen.VB_Description = "Listen for incoming connection requests"
'
Dim lngRetValue As Long 'value returned by the listen Winsock API function
'
On Error GoTo Listen_Err_Handler
'
'SocketExists is not a variable. It is a function that can
'create a socket, if the class has no one.
If Not SocketExists Then Exit Sub
'
'The listen Winsock API function cannot be called
'without the call of the bind one.
If Not m_blnSocketIsBound Then 'Added: 10-MAR-2002
Call Bind
End If 'Added: 10-MAR-2002
'
'Turn the socket into a listening state
lngRetValue = api_listen(m_lngSocketHandle, 5&)
'
If lngRetValue = SOCKET_ERROR Then
mvarState = sckError
'Debug.Print "mvarState = sckError"
Err.Raise Err.LastDllError, "CSocket.Listen", GetErrorDescription(Err.LastDllError)
Else
mvarState = sckListening
'Debug.Print "Listen: mvarState = sckListening"
End If
'
EXIT_LABEL:
'
Exit Sub
'
Listen_Err_Handler:
'
Err.Raise Err.Number, "CSocket.Listen", Err.Description
'
GoTo EXIT_LABEL
'
End Sub
Public Sub GetData(varData As Variant, Optional varType As Variant, Optional maxLen As Variant)
Attribute GetData.VB_Description = "Retrieve data sent by the remote computer"
'
Dim lngBytesReceived As Long 'value returned by the RecvData function
'
On Error GoTo GetData_Err_Handler
'
'A value of the second argument of the RecvData subroutine is False, so in this way
'this procedure will retrieve incoming data from the buffer.
lngBytesReceived = RecvData(varData, False, IIf(IsMissing(varType), Empty, varType), _
IIf(IsMissing(maxLen), Empty, maxLen))
'
EXIT_LABEL:
'
Exit Sub
'
GetData_Err_Handler:
'
Err.Raise Err.Number, "CSocket.GetData", Err.Description
'
GoTo EXIT_LABEL
'
End Sub
Public Sub Connect(Optional strRemoteHost As Variant, Optional lngRemotePort As Variant)
Attribute Connect.VB_Description = "Connect to the remote computer"
'
Dim lngHostAddress As Long '32 bit host address
Dim udtAddress As sockaddr_in 'socket address - used by the connect Winsock API function
Dim lngRetValue As Long 'value returned by the connect Winsock API function
'
On Error GoTo Connect_Err_Handler
'
'If no socket has been created before, try to create a new one
If Not SocketExists Then Exit Sub
'
'If the arguments of this function are not missing, they
'overwrite values of the RemoteHost and RemotePort properties.
'
If Not IsMissing(strRemoteHost) Then 'Added: 04-MAR-2002
If Len(strRemoteHost) > 0 Then
m_strRemoteHost = CStr(strRemoteHost)
End If
End If 'Added: 04-MAR-2002
'
If Not IsMissing(lngRemotePort) Then 'Added: 04-MAR-2002
If IsNumeric(lngRemotePort) Then 'Added: 04-MAR-2002
m_lngRemotePort = CLng(lngRemotePort)
End If 'Added: 04-MAR-2002
End If 'Added: 04-MAR-2002
'
'----------------------------------------------------------
'Added: 31-JUL-2002
'----------------------------------------------------------
If Len(m_strRemoteHost) = 0 Then
Err.Raise sckAddressNotAvailable, "CSocket.Connect", GetErrorDescription(sckAddressNotAvailable)
Exit Sub
End If
'----------------------------------------------------------
'
m_varInternalState = istConnecting
'
'------------------------------------------------------------------
'Modified: 08-JULY-2002
'------------------------------------------------------------------
'Here is a major change. Since version 1.0.6 (08-JULY-2002) the
'SCocket class doesn't try to resolve the IP address into a
'domain name while connecting.
'------------------------------------------------------------------
'
'Try to get 32 bit host address from the RemoteHost property value
lngHostAddress = inet_addr(m_strRemoteHost)
'
If lngHostAddress = INADDR_NONE Then
'
'The RemoteHost property doesn't contain a valid IP address string,
'so that is perhaps a domain name string that we need to resolve
'into IP address
'
'The ResolveHost function, that can be found in the MSocketSupport
'module, will call the WSAAsyncGetHostByName Winsock API function.
'That function is an asynchronous one, so code in this class will be executing
'after the call to the PostGetHostEvent procedure from the WindowProc function
'in the MSupportSocket.
'
'Also, as you can see, the second argument is a pointer to the object, that is
'this instance of the CSocket class. We need this because the callback function
'has to know to which object send the received host infromation. See the code
'in the MSocketSupport module for more information.
'
'Change the State property value
mvarState = sckResolvingHost
'Debug.Print "mvarState = sckResolvingHost"
'
m_lngRequestID = 0
m_lngRequestID = MSocketSupport.ResolveHost(m_strRemoteHost, ObjPtr(Me))
'
'-------------------------------------------------------
'Added: 04-JUNE-2002
'-------------------------------------------------------
If m_lngRequestID = 0 Then
Call DestroySocket
Err.Raise Err.Number, Err.Source, Err.Description
End If
'-------------------------------------------------------
'
Else
'
'The RemoteHost property contains a valid IP address string,
'so we can go on connecting to the remote host.
'
'Build the sockaddr_in structure to pass it to the connect
'Winsock API function as an address of the remote host.
With udtAddress
'
.sin_addr = lngHostAddress
.sin_family = AF_INET
.sin_port = htons(UnsignedToInteger(CLng(m_lngRemotePort)))
'
End With
'
'Call the connect Winsock API function in order to establish connection.
lngRetValue = api_connect(m_lngSocketHandle, udtAddress, Len(udtAddress))
'
'Since the socket we use is a non-blocking one, the connect Winsock API
'function should return a value of SOCKET_ERROR anyway.
'
If lngRetValue = SOCKET_ERROR Then
'
'The WSAEWOULDBLOCK error is OK for such a socket
'
If Not Err.LastDllError = WSAEWOULDBLOCK Then
Err.Raise Err.LastDllError, "CSocket.Connect", GetErrorDescription(Err.LastDllError)
Else
'Change the State property value
mvarState = sckConnecting
'Debug.Print "mvarState = sckConnecting"
End If
'
End If
'
End If
'
EXIT_LABEL:
'
Exit Sub
'
Connect_Err_Handler:
'
Err.Raise Err.Number, "CSocket.CSocket.Connect", Err.Description
'
GoTo EXIT_LABEL
'
End Sub
Public Sub CloseSocket()
Attribute CloseSocket.VB_Description = "Close current connection"
'
Dim lngRetValue As Long 'value returned by the shutdown Winsock API function
'
On Error GoTo Close_Err_Handler
'
'Why do we need to run the code that should not be running?
If m_lngSocketHandle = INVALID_SOCKET Then Exit Sub
'
If Not mvarState = sckConnected Then
'
'If the socket is not connected we can just close it
Call DestroySocket
mvarState = sckClosed
'Debug.Print "mvarState = sckClosed"
'
Else
'
'If the socket is connected, it's another story.
'In order to be sure that no data will be lost the
'graceful shutdown of the socket should be performed.
'
mvarState = sckClosing
'Debug.Print "mvarState = sckClosing"
'
'Call the shutdown Winsock API function in order to
'close the connection. That doesn't mean that the
'connection will be closed after the call of the
'shutdown function. Connection will be closed from
'the PostSocketEvent subroutine when the FD_CLOSE
'message will be received.
'
'For people who know what the FIN segment in the
'TCP header is - this function sends an empty packet
'with the FIN bit turned on.
'
lngRetValue = shutdown(m_lngSocketHandle, SD_SEND)
'
'Debug.Print m_lngSocketHandle & ": shutdown"
'
If lngRetValue = SOCKET_ERROR Then
Err.Raise Err.LastDllError, "CSocket.CloseSocket", GetErrorDescription(Err.LastDllError)
End If
'
End If
EXIT_LABEL:
'
Exit Sub
'
Close_Err_Handler:
'
If Err.Number <> 10038 Then
'Err.Raise Err.Number, "CSocket.Close", Err.Description
End If
'
GoTo EXIT_LABEL
'
End Sub
Public Sub Bind(Optional lngLocalPort As Long, Optional strLocalIP As String)
Attribute Bind.VB_Description = "Binds socket to specific port and adapter"
'
Dim lngRetValue As Long 'value returned by the bind Winsock API function
Dim udtLocalAddr As sockaddr_in 'local socket address to bind to - used by the
' bind Winsock API function
Dim lngAddress As Long '32-bit host address - value returned by
' the inet_addr Winsock API function
'
On Error GoTo Bind_Err_Handler
'
'If no socket has been created before, try to create a new one
If Not SocketExists Then Exit Sub
'
'If the arguments of this function are not missing, they
'overwrites values of the RemoteHost and RemotePort properties.
'
If Len(strLocalIP) > 0 Then
m_strLocalIP = strLocalIP
End If
'
If lngLocalPort > 0 Then
m_lngLocalPort = lngLocalPort
End If
'
If Len(m_strLocalIP) > 0 Then
'
'If the local IP is known, get the address
'from it with the inet_addr Winsock API function.
lngAddress = inet_addr(m_strLocalIP)
'
Else
'
'If the IP is unknown, assign the default interface's IP.
'Actually, this line is useless in Visual Basic code,
'as INADDR_ANY = 0 (IP = 0.0.0.0).
lngAddress = INADDR_ANY
'
End If
'
If lngAddress = SOCKET_ERROR Then
'
'Bad address - go away
Err.Raise Err.LastDllError, "CSocket.Bind", GetErrorDescription(Err.LastDllError)
Exit Sub
'
End If
'
'Prepare the udtLocalAddr UDT that is a socket address structure.
With udtLocalAddr
'
'host address (32-bits value)
.sin_addr = lngAddress
'address family
.sin_family = AF_INET
'port number in the network byte order
.sin_port = htons(UnsignedToInteger(m_lngLocalPort)) 'Modified: 04-JUNE-2002
'
End With
'
'Call the bind Winsock API function in order to assign local address for the socket
lngRetValue = api_bind(m_lngSocketHandle, udtLocalAddr, Len(udtLocalAddr))
'
If lngRetValue = SOCKET_ERROR Then
'
Err.Raise Err.LastDllError, "CSocket.Bind", GetErrorDescription(Err.LastDllError)
'
Else
'
m_blnSocketIsBound = True 'Added: 10-MAR-2002
'
End If
'
EXIT_LABEL:
'
Exit Sub
'
Bind_Err_Handler:
'
Err.Raise Err.Number, "CSocket.Bind", Err.Description
'
GoTo EXIT_LABEL
'
End Sub
Public Sub Accept(requestID As Long)
Attribute Accept.VB_Description = "Accept an incoming connection request"
'
'The requestID argument is provided with the ConnectRequest
'event of another instance of the CSocket class. Actually,
'this argument is a handle of the socket already created
'calling the Accept Winsock API function by that (another)
'instance of the CSocket class.
'
Dim lngRetValue As Long 'value returned by the getsockname, getpeername, and
' getsockopt Winsock API functions
Dim lngBuffer As Long 'the buffer to pass with the getsockopt Winsock API function
Dim udtSockAddr As sockaddr_in 'socket address - used by the getsockname and getpeername
' Winsock API functions
Dim udtHostent As HOSTENT 'structure to hold the host info - returned by the
' getsockname and getpeername Winsock API functions
'
On Error GoTo Accept_Err_Handler
'
'What we need to do in the body of this subroutine is to
'initialize the properties of the class that we can find
'values for. Also we need to register the socket with
'the RegisterSocket function from MSocketSupport module.
'
'Assign the socket handle
m_lngSocketHandle = requestID
'
'Retrieve the connection end-points to initialize
'the following properties of the CSocket class:
'LocalPort, LocalIP, LocalHostName
'RemotePort, RemoteHostIP, RemoteHost
'
'Local end point
'
lngRetValue = getsockname(m_lngSocketHandle, udtSockAddr, Len(udtSockAddr))
'
If lngRetValue = 0 Then
'
'LocalPort property
m_lngLocalPort = IntegerToUnsigned(ntohs(udtSockAddr.sin_port))
'LocalIP property
m_strLocalIP = StringFromPointer(inet_ntoa(udtSockAddr.sin_addr))
'LocalHostName property
'----------------------------------------------------------------
'Modified: 31-JUL-2002
'----------------------------------------------------------------
'lngRetValue = gethostbyaddr(udtSockAddr.sin_addr, 4&, AF_INET)
'CopyMemory udtHostent, ByVal lngRetValue, Len(udtHostent)
'm_strLocalHostName = StringFromPointer(udtHostent.hName)
m_strLocalHostName = m_strLocalIP
'----------------------------------------------------------------
'
End If
'
'Remote end point
'
lngRetValue = getpeername(m_lngSocketHandle, udtSockAddr, Len(udtSockAddr))
'
If lngRetValue = 0 Then
'
'RemotePort property
m_lngRemotePort = IntegerToUnsigned(ntohs(udtSockAddr.sin_port))
'RemoteHostIP property
m_strRemoteHostIP = StringFromPointer(inet_ntoa(udtSockAddr.sin_addr))
'RemoteHost property
'----------------------------------------------------------------
'Modified: 31-JUL-2002
'----------------------------------------------------------------
'lngRetValue = gethostbyaddr(udtSockAddr.sin_addr, 4&, AF_INET)
'CopyMemory udtHostent, ByVal lngRetValue, Len(udtHostent)
'm_strRemoteHost = StringFromPointer(udtHostent.hName)
m_strRemoteHost = m_strRemoteHostIP
'----------------------------------------------------------------
'
End If
'
'Retrieve the socket type to initialize the Protocol property
lngRetValue = getsockopt(m_lngSocketHandle, SOL_SOCKET, SO_TYPE, lngBuffer, LenB(lngBuffer))
'
If lngRetValue <> SOCKET_ERROR Then
'
If lngBuffer = SOCK_STREAM Then
mvarProtocol = sckTCPProtocol
Else
mvarProtocol = sckUDPProtocol
End If
'
End If
'
'Get default size of the Winsock's buffers.
Call GetWinsockBuffers 'Added: 10-MAR-2002
'
If MSocketSupport.RegisterSocket(m_lngSocketHandle, ObjPtr(Me)) Then
'
'Change the State property value
mvarState = sckConnected
'Debug.Print "Accept: mvarState = sckConnected"
'
End If
'
EXIT_LABEL:
'
Exit Sub
'
Accept_Err_Handler:
'
Err.Raise Err.Number, "CSocket.Accept", Err.Description
'
GoTo EXIT_LABEL
'
End Sub
Public Property Get State() As StateConstants
State = mvarState
End Property
Public Property Get SocketHandle() As Long
Attribute SocketHandle.VB_Description = " Returns the socket handle"
SocketHandle = m_lngSocketHandle
End Property
Public Property Get RemotePort() As Long
Attribute RemotePort.VB_Description = "Returns/Sets the port to be connected to on the remote computer"
RemotePort = m_lngRemotePort
End Property
Public Property Let RemotePort(NewValue As Long)
m_lngRemotePort = NewValue
End Property
Public Property Get RemoteHostIP() As String
Attribute RemoteHostIP.VB_Description = "Returns the remote host IP address"
RemoteHostIP = m_strRemoteHostIP
End Property
Public Property Get RemoteHost() As String
Attribute RemoteHost.VB_Description = "Returns/Sets the name used to identify the remote computer"
RemoteHost = m_strRemoteHost
End Property
Public Property Let RemoteHost(NewValue As String)
'
Dim lngHostAddress As Long '32 bit host address
Dim lngRetValue As Long 'value returned by the setsockopt function
'
m_strRemoteHost = NewValue
'
If Len(NewValue) > 0 Then
'
'Check for a valid IP address string
'
lngHostAddress = inet_addr(NewValue)
'
If Not lngHostAddress = INADDR_NONE Then
'
m_strRemoteHostIP = NewValue
'
If Not mvarProtocol = sckUDPProtocol Then Exit Property
If Not SocketExists Then Exit Property
'
'If the IP address is a brodcasting one set the option
'
If Right(NewValue, 4) = ".255" And m_blnBroadcast = False Then
'
lngRetValue = setsockopt(m_lngSocketHandle, SOL_SOCKET, SO_BROADCAST, 1&, 4&)
'
If lngRetValue = SOCKET_ERROR Then
'
With Err
.Raise .LastDllError, "CSocket.RemoteHost", GetErrorDescription(.LastDllError)
End With
'
Else
'
m_blnBroadcast = True
'
End If
'
ElseIf (Not (Right(NewValue, 4) = ".255")) And (m_blnBroadcast = True) Then
'
lngRetValue = setsockopt(m_lngSocketHandle, SOL_SOCKET, SO_BROADCAST, 0&, 4&)
'
If lngRetValue = SOCKET_ERROR Then
'
With Err
.Raise .LastDllError, "CSocket.RemoteHost", GetErrorDescription(.LastDllError)
End With
'
Else
'
m_blnBroadcast = False
'
End If
'
End If
'
End If
'
End If
'
End Property
Public Property Get Protocol() As ProtocolConstants
Attribute Protocol.VB_Description = "Returns/Sets the socket protocol"
Protocol = mvarProtocol
End Property
Public Property Let Protocol(NewValue As ProtocolConstants)
'
If m_lngSocketHandle = INVALID_SOCKET Then 'Modified: 10-MAR-2002
mvarProtocol = NewValue
End If
'
End Property
Public Property Get LocalPort() As Long
Attribute LocalPort.VB_Description = "Returns/Sets the port used on the local computer"
LocalPort = m_lngLocalPort
End Property
Public Property Let LocalPort(NewValue As Long)
m_lngLocalPort = NewValue
End Property
Public Property Get LocalIP() As String
Attribute LocalIP.VB_Description = "Returns the local machine IP address"
LocalIP = m_strLocalIP
End Property
Public Property Get LocalHostName() As String
Attribute LocalHostName.VB_Description = "Returns the local machine name"
LocalHostName = m_strLocalHostName
End Property
Public Property Get BytesReceived() As Long
Attribute BytesReceived.VB_Description = "Returns the number of bytes received on this connection"
BytesReceived = m_lngBytesReceived
End Property
Private Sub Class_Initialize()
'
'Socket's handle default value
m_lngSocketHandle = INVALID_SOCKET
'Initialize the Winsock service
m_lngMaxMsgSize = MSocketSupport.InitWinsockService
'
End Sub
Public Function vbSocket() As Long
'********************************************************************************
'Author :Oleg Gdalevich
'Purpose :Creates a new socket
'Returns :The socket handle if successful, otherwise - INVALID_SOCKET
'Arguments :
'********************************************************************************
'
On Error GoTo vbSocket_Err_Handler
'
Dim lngRetValue As Long 'value returned by the socket API function
'
'Call the socket Winsock API function in order to create a new socket
If mvarProtocol = sckUDPProtocol Then
lngRetValue = api_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
Else
lngRetValue = api_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
End If
'
If lngRetValue = INVALID_SOCKET Then
'
Err.Raise Err.LastDllError, "CSocket.vbSocket", GetErrorDescription(Err.LastDllError)
'
Else
'
'Debug.Print lngRetValue & ": socket created"
'
If Not MSocketSupport.RegisterSocket(lngRetValue, ObjPtr(Me)) Then 'Modified: 04-JUNE-2002
'--------------------------------------------------
'Added: 04-JUNE-2002
'--------------------------------------------------
lngRetValue = INVALID_SOCKET
Call api_closesocket(lngRetValue)
Err.Raise Err.Number, Err.Source, Err.Description
'--------------------------------------------------
'
End If
'
End If
'
'Assign returned value
vbSocket = lngRetValue
'
EXIT_LABEL:
Exit Function
vbSocket_Err_Handler:
'
vbSocket = INVALID_SOCKET
'
End Function
Friend Sub PostSocketEvent(ByVal lngEventID As Long, Optional ByVal lngError As Long)
'
'This procedure is called by the WindowProc callback function
'from the MSocketSupport module. The lngEventID argument is an
'ID of the network event occurred for the socket. The lngError
'argument contains an error code only if an error was occurred
'during an asynchronous execution.
'
Dim lngBytesReceived As Long 'value returned by the RecvDataToBuffer function
Dim lngRetValue As Long 'value returned by the getsockname Winsock API function
Dim lngNewSocket As Long 'value returned by the accept Winsock API function
Dim udtSockAddr As sockaddr_in 'remote socket address for the accept Winscok API function
Dim udtHostent As HOSTENT 'structure to hold the host info - returned
' by the gethostbyaddr Winsock API function
'
On Error GoTo ERROR_HANDLER
'
If lngError > 0 Then
'
'An error was occurred.
'
'Change a value of the State property
mvarState = sckError
'Debug.Print "mvarState = sckError"
'Close the socket
Call DestroySocket
'The OnError event is just for this case
RaiseEvent OnError(CInt(lngError), GetErrorDescription(lngError), 0, "", "", 0, False)
'We have nothing to do here anymore
Exit Sub
'
End If
'
Select Case lngEventID
'