1 #Region "Microsoft.VisualBasic::7df5133cf193440cc424d4910049216c, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\TCPExtensions.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Module TCPExtensions
35     
36     '         Function: BuildOAuth, ConnectSocket, GetCA, GetFirstAvailablePort, (+2 Overloads) Ping
37     '                   PortIsAvailable, PortIsUsed
38     
39     
40     ' /********************************************************************************/
41
42 #End Region
43
44 Imports System.Net
45 Imports System.Net.NetworkInformation
46 Imports System.Net.Sockets
47 Imports System.Reflection
48 Imports System.Runtime.CompilerServices
49 Imports Microsoft.VisualBasic.Linq.Extensions
50 Imports Microsoft.VisualBasic.Net.Http
51 Imports Microsoft.VisualBasic.Net.Protocols
52 Imports Microsoft.VisualBasic.Serialization.JSON
53
54 Namespace Net
55
56     Public Module TCPExtensions
57
58         ''' <summary>
59         ''' -1标识Ping不通
60         ''' </summary>
61         ''' <param name="operationTimeOut">ms</param>
62         ''' <returns></returns>
63         Public Function Ping(ep As System.Net.IPEndPoint, Optional operationTimeOut As Integer = 3 * 1000) As Double
64             Return New AsynInvoke(ep).Ping(operationTimeOut)
65         End Function
66
67         ''' <summary>
68         ''' -1 ping failure
69         ''' </summary>
70         ''' <param name="invoke"></param>
71         ''' <param name="timeout"></param>
72         ''' <returns></returns>
73         <Extension>
74         Public Function Ping(invoke As AsynInvoke, Optional timeout As Integer = 3 * 1000) As Double
75             Dim sw As Stopwatch = Stopwatch.StartNew
76             Dim request As RequestStream = RequestStream.SystemProtocol(RequestStream.Protocols.Ping, PING_REQUEST)
77             Dim response As RequestStream = invoke.SendMessage(request, timeOut:=timeout)
78
79             If HTTP_RFC.RFC_REQUEST_TIMEOUT = response.Protocol Then
80                 Return -1
81             End If
82
83             Return sw.ElapsedMilliseconds
84         End Function
85
86         Public Const PING_REQUEST As String = "PING/TTL-78973"
87
88         ''' <summary>
89         ''' 假若不能成功的建立起连接的话,则会抛出错误
90         ''' </summary>
91         ''' <param name="server"></param>
92         ''' <param name="port"></param>
93         ''' <returns></returns>
94         ''' <remarks></remarks>
95         Public Function ConnectSocket(server As String, port As IntegerAs System.Net.IPEndPoint
96
97             Get host related information.
98             Dim HostEntry As IPHostEntry = Dns.GetHostEntry(server)
99
100             Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
101             ' an exception that occurs when the host host IP Address is not compatible with the address family
102             ' (typical in the IPv6 case).
103             For Each Address As IPAddress In HostEntry.AddressList
104                 Dim endPoint As New System.Net.IPEndPoint(Address, port)
105                 Dim Socket As Socket = New Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
106
107                 Try
108                     Call Socket.Connect(endPoint)
109                 Catch ex As Exception
110                     Continue For
111                 End Try
112
113                 If Socket.Connected Then
114                     Return endPoint
115                 End If
116             Next
117
118             Throw New Exception(String.Format("The target connection to {0}:{1} can not be made!", server, port))
119         End Function
120
121         Const MAX_PORT As Integer = 65535    '系统tcp/udp端口数最大是65535
122
123         ''' <summary>
124         ''' Get the first available TCP port on this local machine.
125         ''' (获取第一个可用的端口号,请注意,在高并发状态下可能会出现端口被占用的情况,
126         ''' 所以这时候建议将<paramref name="BEGIN_PORT"/>设置为-1,则本函数将会尝试使用随机数来分配可用端口,从而避免一些系统崩溃的情况产生)
127         ''' </summary>
128         ''' <param name="BEGIN_PORT">Check the local port available from this port value.(从这个端口开始检测)</param>
129         ''' <returns></returns>
130         Public Function GetFirstAvailablePort(Optional BEGIN_PORT As Integer = 100) As Integer
131             If BEGIN_PORT <= 0 Then
132                 BEGIN_PORT = Rnd() * (MAX_PORT - 1)  ' 为了避免高并发的时候出现端口占用的情况,在这里使用随机数来解决一些问题
133             End If
134
135             For i As Integer = BEGIN_PORT To MAX_PORT - 1
136                 If PortIsAvailable(port:=i) Then
137                     Return i
138                 End If
139             Next
140
141             Return -1
142         End Function
143
144         ''' <summary>
145         ''' 获取操作系统已用的端口号
146         ''' </summary>
147         ''' <returns></returns>
148         Public Function PortIsUsed() As Integer()
149             '获取本地计算机的网络连接和通信统计数据的信息
150             Dim ipGlobalProperties__1 As IPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties()
151
152             '返回本地计算机上的所有Tcp监听程序
153             Dim ipsTCP As System.Net.IPEndPoint() = ipGlobalProperties__1.GetActiveTcpListeners()
154
155             '返回本地计算机上的所有UDP监听程序
156             Dim ipsUDP As System.Net.IPEndPoint() = ipGlobalProperties__1.GetActiveUdpListeners()
157
158             '返回本地计算机上的Internet协议版本4(IPV4 传输控制协议(TCP)连接的信息。
159             Dim tcpConnInfoArray As TcpConnectionInformation() = ipGlobalProperties__1.GetActiveTcpConnections()
160
161             Dim allPorts As List(Of Integer) = New List(Of Integer)
162             Call allPorts.AddRange((From ep As System.Net.IPEndPoint In ipsTCP Select ep.Port).ToArray)
163             Call allPorts.AddRange((From ep As System.Net.IPEndPoint In ipsUDP Select ep.Port).ToArray)
164             Call allPorts.AddRange((From conn As TcpConnectionInformation In tcpConnInfoArray Select conn.LocalEndPoint.Port).ToArray)
165
166             Return allPorts.ToArray
167         End Function
168
169         ''' <summary>
170         ''' 检查指定端口是否已用
171         ''' </summary>
172         ''' <param name="port"></param>
173         ''' <returns></returns>
174         Public Function PortIsAvailable(port As IntegerAs Boolean
175             Dim portUsed As Integer() = PortIsUsed()
176
177             For Each p As Integer In portUsed
178                 If p = port Then
179                     Return False
180                 End If
181             Next
182
183             Return True
184         End Function
185
186 #Region "OAuth Arguments"
187
188         Const hash As String = "hash"
189         Const uid As String = "uid"
190
191         <Extension> Public Function BuildOAuth(ca As Net.SSL.Certificate) As String
192             Dim array As KeyValuePair(Of StringString)() = {
193                 New KeyValuePair(Of StringString)(hash, ca.PrivateKey),
194                 New KeyValuePair(Of StringString)(uid, ca.uid)
195             }
196             Dim oauth As String = WebServiceUtils.BuildUrlData(array)
197             Return oauth
198         End Function
199
200         <Extension> Public Function GetCA(args As StringAs Net.SSL.Certificate
201 #If DEBUG Then
202             Call $"{MethodBase.GetCurrentMethod.GetFullName} ==> {args}".__DEBUG_ECHO
203 #End If
204             Dim data = WebServiceUtils.QueryStringParameters(args, False)
205 #If DEBUG Then
206             Call data.AllKeys.Select(Function(k) data(k)).ToArray.GetJson.__DEBUG_ECHO
207 #End If
208             Dim privateKey As String = data(hash)
209             Dim uid As Long = Scripting.CTypeDynamic(Of Long)(data(TCPExtensions.uid))
210             Return Net.SSL.Certificate.Install(privateKey, uid)
211         End Function
212 #End Region
213     End Module
214 End Namespace