Utilities.vb 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. Public Class Utilities
  2. Public Shared Function BytesToString(ByVal data() As Byte) As String
  3. 'Dim enc As New System.Text.UTF8Encoding()
  4. 'BytesToString = enc.GetString(data)
  5. Return System.Text.UTF8Encoding.UTF8.GetString(data)
  6. End Function
  7. Public Shared Function StrToByteArray(ByVal text As String) As Byte()
  8. 'Dim encoding As New System.Text.UTF8Encoding()
  9. 'StrToByteArray = encoding.GetBytes(text)
  10. Return System.Text.UTF8Encoding.UTF8.GetBytes(text)
  11. End Function
  12. Public Class LargeArrayTransferHelper
  13. Private client As TcpComm.Client
  14. Private server As TcpComm.Server
  15. Private isServer As Boolean
  16. Private incommingMessages As List(Of IncomingMessage)
  17. Private serverCallback As TcpComm.Server.ServerCallbackDelegate
  18. Private clientCallback As TcpComm.Client.ClientCallbackDelegate
  19. Private signatureBytes() As Byte
  20. Private incommingMessageLock As New Object
  21. Private Class IncomingMessage
  22. Public channel As Byte
  23. Public sessionId As Integer
  24. Public length As Integer
  25. Public bytes As System.IO.MemoryStream
  26. End Class
  27. Sub New(ByRef _client As TcpComm.Client)
  28. client = _client
  29. clientCallback = client.ClientCallbackObject
  30. isServer = False
  31. Init()
  32. End Sub
  33. Sub New(ByRef _server As TcpComm.Server)
  34. server = _server
  35. isServer = True
  36. serverCallback = server.ServerCallbackObject
  37. Init()
  38. End Sub
  39. Private Sub Init()
  40. incommingMessages = New List(Of IncomingMessage)
  41. signatureBytes = StrToByteArray("<utility=LargeArrayTransferHelperV1.0")
  42. End Sub
  43. Private Function VerifySignature(ByRef bytes() As Byte) As Boolean
  44. If bytes.Length < signatureBytes.Length then Return False
  45. Dim verifyed As Boolean = True
  46. For count As Int32 = 0 to signatureBytes.Length - 1
  47. If bytes(count) <> signatureBytes(count) then
  48. verifyed = False
  49. Exit For
  50. End If
  51. Next
  52. Return verifyed
  53. End Function
  54. ''' <summary>
  55. ''' Put this at the top of your callback, in a if statement. If it eveluates to true, then call return (the bytes were handled by this method). This method will
  56. ''' eveluate all incoming packets within the channelrange, and assemble any large arrays sent. When one is complete, it will call the callback itself for you,
  57. ''' and hand you the completed large array.
  58. ''' Ie:
  59. '''
  60. ''' If lat.HandleIncomingBytes(bytes, dataChannel) then Return
  61. '''
  62. ''' </summary>
  63. ''' <param name="bytes">The bytes supplied by your callback.</param>
  64. ''' <param name="channel">The channel supplied by your callback.</param>
  65. ''' <param name="sessionId">The sessionId supplied by your callback - obviously just for servers.</param>
  66. ''' <param name="channelRange">This byte array should contain two elements. The first is the lowest chanel this function should evaluate, the second is the highest.
  67. ''' Leave it blank to eveluate all valid channels. However, not specifying a channelRange may slow down comunications.</param>
  68. ''' <returns>A boolean value indication weather or not this incoming packet was handled by this function.</returns>
  69. ''' <remarks></remarks>
  70. Public Function HandleIncomingBytes(ByVal bytes As Byte(), ByVal channel As Byte, Optional ByVal sessionId As Integer = -1, Optional ByVal channelRange() As Byte = Nothing) As Boolean
  71. If channelRange IsNot Nothing Then
  72. ' Is channelRange valid?
  73. If channelRange.Count <> 2 Then
  74. MsgBox("When using TcpComm.LargeArrayTransferHelper.HandleIncomingBytes(), channelRange must be a byte array that has two elements. See the xml parameter information for details.", _
  75. MsgBoxStyle.Critical, "TcpComm.LargeArrayTransferHelper error")
  76. Return False
  77. End If
  78. ' Are the channels supplied valid?
  79. If channelRange(0) < 1 Or channelRange(1) > 251 Then
  80. MsgBox("When using TcpComm.LargeArrayTransferHelper.HandleIncomingBytes(), channelRange must be a byte array that has two elements. See the xml parameter information for details.", _
  81. MsgBoxStyle.Critical, "TcpComm.LargeArrayTransferHelper error")
  82. Return False
  83. End If
  84. ' Are we eveluating data on this channel?
  85. If channelRange IsNot Nothing And channel < channelRange(0) Or channel > channelRange(1) Then Return False
  86. End If
  87. ' Check to see if we're receiving an incoming large array header:
  88. If VerifySignature(bytes) Then
  89. Dim msg As String = BytesToString(bytes)
  90. Dim msgParts() As String
  91. Dim length As Integer = 0
  92. Dim incomingChanel As Byte
  93. ' Get the incoming array size and channel from the lat helper header:
  94. msg = msg.Replace("<utility=LargeArrayTransferHelperV1.0", "")
  95. msg = msg.Replace(">", "")
  96. msgParts = msg.Split(",")
  97. For Each part As String In msgParts
  98. If part.Contains("arraysize=") Then
  99. part = part.Replace("arraysize=", "")
  100. length = Convert.ToInt32(part)
  101. End If
  102. If part.Contains("channel=") Then
  103. part = part.Replace("channel=", "")
  104. incomingChanel = Convert.ToByte(part)
  105. End If
  106. Next
  107. ' Add this large array job to our incommingMessages list:
  108. SyncLock incommingMessageLock
  109. incommingMessages.Add(New IncomingMessage With { _
  110. .channel = incomingChanel,
  111. .bytes = New System.IO.MemoryStream(length),
  112. .length = length,
  113. .sessionId = sessionId
  114. })
  115. End SyncLock
  116. ' Return true so we know not to
  117. ' process this in the callback.
  118. Return True
  119. End If
  120. SyncLock incommingMessageLock
  121. ' It's not a LAT header. Are we handling this packet?
  122. If incommingMessages.Count = 0 Then Return False
  123. Dim removeThis As IncomingMessage = Nothing
  124. Dim handledThis As Boolean = False
  125. ' Search our list of incoming large arrays to see if we should handle this message
  126. For Each message As IncomingMessage In incommingMessages
  127. If message.channel = channel And message.sessionId = sessionId Then
  128. handledThis = True
  129. message.bytes.Write(bytes, 0, bytes.Length)
  130. ' Are we finished?
  131. If message.length = message.bytes.Length Then
  132. ' Do a callback from a background thread to avoid a deadlock.
  133. Dim doCallback As New Threading.Thread(AddressOf bgCallback)
  134. doCallback.Start(message)
  135. removeThis = message
  136. Exit For
  137. End If
  138. End If
  139. Next
  140. If removeThis IsNot Nothing Then incommingMessages.Remove(removeThis)
  141. If handledThis Then Return True
  142. Return False
  143. End SyncLock
  144. End Function
  145. Private Sub bgCallback(ByVal msg As Object)
  146. Dim message As IncomingMessage = CType(msg, IncomingMessage)
  147. If isServer then
  148. serverCallback(message.bytes.ToArray().Clone(), message.sessionId, message.channel)
  149. Else
  150. clientCallback(message.bytes.ToArray().Clone(), message.channel)
  151. End If
  152. End Sub
  153. Public Function SendArray(ByVal bytes As Byte(), ByVal channel As Byte, Optional ByRef errMsg As String = "") As Boolean
  154. Return SendArray(bytes, channel, -1, errMsg)
  155. End Function
  156. Public Function SendArray(ByVal bytes As Byte(), ByVal channel As Byte, ByVal sessionId As Integer, ByRef errMsg As String) As Boolean
  157. Dim header As String = String.Format("<utility=LargeArrayTransferHelperV1.0,arraysize={0},channel={1}>", _
  158. bytes.Length.ToString(), channel.ToString())
  159. If isServer Then
  160. If sessionId < 0 Then
  161. errMsg = sessionId.ToString & " is an invalid value for sessionId. To send a large array from the server, you must specify a sessionId."
  162. Return False
  163. End If
  164. If channel < 1 Or channel > 251 Then
  165. errMsg = channel.ToString & " is an invalid channel."
  166. Return False
  167. End If
  168. If Not server.SendText(header, channel, sessionId, errMsg) Then Return False
  169. If Not server.SendBytes(bytes, channel, sessionId, errMsg) Then Return False
  170. Else
  171. If channel < 1 Or channel > 251 Then
  172. errMsg = channel.ToString & " is an invalid channel."
  173. Return False
  174. End If
  175. If Not client.SendText(header, channel, errMsg) Then Return False
  176. If Not client.SendBytes(bytes, channel, errMsg) Then Return False
  177. End If
  178. Return True
  179. End Function
  180. End Class
  181. End Class