TcpComm.vb 112 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865
  1. Imports System.Threading
  2. Imports System.Net
  3. Imports System.Net.Sockets
  4. Imports System.IO
  5. Imports System.Collections.Concurrent
  6. Imports System.Reflection
  7. Imports System.Runtime.InteropServices
  8. Imports System.Diagnostics
  9. Imports System.Collections.Generic
  10. Public Class TcpComm
  11. Public Shared Function BytesToString(ByVal data() As Byte) As String
  12. Dim enc As New System.Text.UTF8Encoding()
  13. BytesToString = enc.GetString(data)
  14. End Function
  15. Public Shared Function StrToByteArray(ByVal text As String) As Byte()
  16. Dim encoding As New System.Text.UTF8Encoding()
  17. StrToByteArray = encoding.GetBytes(text)
  18. End Function
  19. Public Class clsAsyncUnbuffWriter
  20. '''' We need the page size for best performance - so we use GetSystemInfo and dwPageSize
  21. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  22. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  23. Public Class clsSystemInfo
  24. private Class WinApi
  25. <DllImport("kernel32.dll")> _
  26. Public Shared Sub GetSystemInfo(<MarshalAs(UnmanagedType.Struct)> ByRef lpSystemInfo As SYSTEM_INFO)
  27. End Sub
  28. <StructLayout(LayoutKind.Sequential)> _
  29. Public Structure SYSTEM_INFO
  30. Friend uProcessorInfo As _PROCESSOR_INFO_UNION
  31. Public dwPageSize As UInteger
  32. Public lpMinimumApplicationAddress As IntPtr
  33. Public lpMaximumApplicationAddress As IntPtr
  34. Public dwActiveProcessorMask As IntPtr
  35. Public dwNumberOfProcessors As UInteger
  36. Public dwProcessorType As UInteger
  37. Public dwAllocationGranularity As UInteger
  38. Public dwProcessorLevel As UShort
  39. Public dwProcessorRevision As UShort
  40. End Structure
  41. <StructLayout(LayoutKind.Explicit)> _
  42. Public Structure _PROCESSOR_INFO_UNION
  43. <FieldOffset(0)> _
  44. Friend dwOemId As UInteger
  45. <FieldOffset(0)> _
  46. Friend wProcessorArchitecture As UShort
  47. <FieldOffset(2)> _
  48. Friend wReserved As UShort
  49. End Structure
  50. End Class
  51. Public Shared Function GetPageSize() As Integer
  52. Dim sysinfo As New WinApi.SYSTEM_INFO()
  53. WinApi.GetSystemInfo(sysinfo)
  54. Return CInt(sysinfo.dwPageSize)
  55. End Function
  56. End Class
  57. Private target As FileStream
  58. Private inputBuffer As MemoryStream
  59. Private bufferSize As Integer
  60. Private running As Boolean
  61. Private writing As Boolean
  62. Private readWait As Threading.ManualResetEvent
  63. Private writeWait As Threading.ManualResetEvent
  64. Private finishedWriting As Threading.ManualResetEvent
  65. Private totalWritten As Int64
  66. Private writeTimer As Stopwatch
  67. Public Function GetTotalBytesWritten() As Int64
  68. Return totalWritten
  69. End Function
  70. Public Function IsRunning() As Boolean
  71. Return running
  72. End Function
  73. Public Sub Close()
  74. writing = False
  75. writeWait .Set
  76. finishedWriting.WaitOne
  77. readWait .Set
  78. End Sub
  79. Public Function GetActiveMiliseconds() As Int64
  80. Try
  81. Return writeTimer.ElapsedMilliseconds
  82. Catch ex As Exception
  83. Return 0
  84. End Try
  85. End Function
  86. Public Shared Function GetPageSize() As Integer
  87. Return clsSystemInfo.GetPageSize
  88. End Function
  89. Public Sub new(ByVal dest As String, _
  90. Optional ByVal unbuffered As Boolean = False, _
  91. Optional ByVal _bufferSize As Integer = (1024 * 1024), _
  92. Optional ByVal setLength As Int64 = 0)
  93. bufferSize = _bufferSize
  94. Dim options As FileOptions = FileOptions.SequentialScan
  95. If unbuffered then options = FileOptions.WriteThrough or FileOptions.SequentialScan
  96. readWait = New Threading.ManualResetEvent(False)
  97. writeWait = New Threading.ManualResetEvent(False)
  98. finishedWriting = New Threading.ManualResetEvent(False)
  99. readWait .Set
  100. writeWait .Reset
  101. finishedWriting .Reset
  102. target = New FileStream(dest, _
  103. FileMode.Create, FileAccess.Write, FileShare.None, GetPageSize, options)
  104. If setLength > 0 then target.SetLength(setLength)
  105. totalWritten = 0
  106. inputBuffer = New MemoryStream(bufferSize)
  107. running = True
  108. writing = True
  109. writeTimer = New Stopwatch
  110. Dim asyncWriter As New Threading.Thread(AddressOf WriteThread)
  111. With asyncWriter
  112. .Priority = Threading.ThreadPriority.Lowest
  113. .IsBackground = True
  114. .Name = "AsyncCopy writer"
  115. .Start()
  116. End With
  117. End Sub
  118. Public Function Write(ByVal someBytes() As Byte, numToWrite As Integer) As Boolean
  119. If Not running then Return False
  120. If numToWrite < 1 then Return False
  121. If numToWrite > inputBuffer.Capacity then
  122. Throw New Exception("clsAsyncUnbuffWriter: someBytes() can not be larger then buffer capacity")
  123. End If
  124. If (inputBuffer.Length + numToWrite) > inputBuffer.Capacity then
  125. If inputBuffer.Length > 0 then
  126. readWait .Reset
  127. writeWait .Set
  128. readWait .WaitOne
  129. If Not running then Return False
  130. inputBuffer.Write(someBytes, 0, numToWrite)
  131. End If
  132. Else
  133. inputBuffer.Write(someBytes, 0, numToWrite)
  134. End If
  135. Return True
  136. End Function
  137. Private Sub WriteThread()
  138. Dim bytesThisTime As Int32 = 0
  139. Dim internalBuffer(bufferSize) As byte
  140. writeTimer .Stop
  141. writeTimer .Reset
  142. writeTimer .Start
  143. Do
  144. writeWait .WaitOne
  145. writeWait .Reset
  146. bytesThisTime = CInt(inputBuffer.Length)
  147. Buffer.BlockCopy(inputBuffer.GetBuffer, 0, internalBuffer, 0, bytesThisTime)
  148. inputBuffer .SetLength(0)
  149. readWait .Set()
  150. target.Write(internalBuffer, 0, bytesThisTime)
  151. totalWritten += bytesThisTime
  152. Loop While writing
  153. ' Flush inputBuffer
  154. If inputBuffer.Length > 0 then
  155. bytesThisTime = CInt(inputBuffer.Length)
  156. Buffer.BlockCopy(inputBuffer.GetBuffer, 0, internalBuffer, 0, bytesThisTime)
  157. target.Write(internalBuffer, 0, bytesThisTime)
  158. totalWritten += bytesThisTime
  159. End If
  160. running = False
  161. writeTimer .Stop
  162. Try
  163. target .Close
  164. target .Dispose
  165. Catch ex As Exception
  166. End Try
  167. finishedWriting .Set
  168. inputBuffer .Close()
  169. inputBuffer .Dispose()
  170. inputBuffer = Nothing
  171. internalBuffer = Nothing
  172. target = Nothing
  173. GC.GetTotalMemory(True)
  174. End Sub
  175. End Class
  176. Public Class Server
  177. Public errMsg As String
  178. ' Define the callback delegate type
  179. Public Delegate Sub ServerCallbackDelegate(ByVal bytes() As Byte, ByVal sessionID As Int32, ByVal dataChannel As Byte)
  180. 'Private Delegate Sub SendQueueDelegate(ByVal bytes() As Byte, ByVal dataChannel As Byte, ByVal sessionID As Int32)
  181. ' Create Delegate object
  182. Public ServerCallbackObject As ServerCallbackDelegate
  183. 'Private SendCallback As SendQueueDelegate
  184. Private Listener As TcpListener
  185. Private continue_running As Boolean = False
  186. Private blockSize As UInt16
  187. Private Port As Integer
  188. Private localAddr As IPAddress
  189. Private Mbps As UInt32
  190. Private newSessionId As Int32 = 0
  191. Public IsRunning As Boolean = False
  192. Private serverState As currentState = currentState.stopped
  193. Public Class message
  194. Public bytes() As Byte
  195. Public dataChannel As Byte
  196. Public sessionID As Int32
  197. End Class
  198. Private Enum currentState
  199. err = -1
  200. stopped = 0
  201. running = 1
  202. idle = 2
  203. End Enum
  204. Private Class Sessions
  205. Private sessionCollection As New List(Of SessionCommunications)
  206. Private sessionLockObject As New Object
  207. Private reusableSessions As New Concurrent.ConcurrentQueue(Of Int32)
  208. Public Sub AddSession(ByVal theNewSession as SessionCommunications)
  209. Dim thisTask = System.Threading.Tasks.Task.Factory
  210. thisTask.StartNew(Sub()
  211. bgAddSession(theNewSession)
  212. End Sub)
  213. End Sub
  214. Public Function GetReusableSessionID() As Int32
  215. Dim sessionNumber As Int32 = -1
  216. If reusableSessions.TryDequeue(sessionNumber) then
  217. Return sessionNumber
  218. End If
  219. Return -1
  220. End Function
  221. Private Sub bgAddSession(ByVal theNewSession As SessionCommunications)
  222. SyncLock sessionLockObject
  223. If sessionCollection.Count > theNewSession.sessionID then
  224. sessionCollection.Item(theNewSession.sessionID) = Nothing
  225. sessionCollection.Item(theNewSession.sessionID) = theNewSession
  226. Else
  227. sessionCollection.Add(theNewSession)
  228. End If
  229. End SyncLock
  230. End Sub
  231. Public Sub ReuseSessionNumber(ByVal sessionNumber As Int32)
  232. reusableSessions.Enqueue(sessionNumber)
  233. End Sub
  234. Public Function GetSession(ByVal sessionID As Int32, ByRef session As SessionCommunications) As Boolean
  235. Try
  236. session = sessionCollection.Item(sessionID)
  237. If session is Nothing then Return False
  238. If Not session.IsRunning then Return False
  239. Return True
  240. Catch ex As Exception
  241. Return False
  242. End Try
  243. End Function
  244. Public Function GetSession(ByVal MachineID As String, ByRef session As SessionCommunications) As Boolean
  245. session = Nothing
  246. SyncLock sessionLockObject
  247. For Each connectedSession In sessionCollection
  248. If connectedSession.IsRunning and connectedSession.machineId = MachineID then
  249. session = connectedSession
  250. Exit For
  251. End If
  252. Next
  253. End SyncLock
  254. If session is Nothing then Return False
  255. Return True
  256. End Function
  257. Public Sub Broadcast(ByVal msg As message)
  258. Dim thisCopy As New List(Of SessionCommunications)
  259. SyncLock sessionLockObject
  260. For i As Int32 = 0 to sessionCollection.Count - 1
  261. thisCopy.Add(sessionCollection.Item(i))
  262. Next
  263. End SyncLock
  264. For i As Int32 = 0 To thisCopy.Count - 1
  265. If thisCopy.Item(i) IsNot Nothing AndAlso thisCopy.Item(i).IsRunning Then
  266. Try
  267. thisCopy.Item(i).sendQueue.Enqueue(msg)
  268. Catch ex As Exception
  269. End Try
  270. End If
  271. Next
  272. End Sub
  273. Public Function GetSessionCollection() As List(Of SessionCommunications)
  274. Dim thisCopy As New List(Of SessionCommunications)
  275. SyncLock sessionLockObject
  276. For i As Int32 = 0 to sessionCollection.Count - 1
  277. 'If sessionCollection.Item(i).IsRunning then thisCopy.Add(sessionCollection.Item(i))
  278. thisCopy.Add(sessionCollection.Item(i))
  279. Next
  280. End SyncLock
  281. Return thisCopy
  282. End Function
  283. Public Sub ShutDown()
  284. SyncLock sessionLockObject
  285. For Each session As SessionCommunications In sessionCollection
  286. Try
  287. If session IsNot Nothing AndAlso session.IsRunning Then session.Close()
  288. Catch ex As Exception
  289. End Try
  290. Next
  291. End SyncLock
  292. End Sub
  293. End Class
  294. Public Class SessionCommunications
  295. Public UserBytesToBeSentAvailable As Boolean = False
  296. Public UserBytesToBeSent As New MemoryStream
  297. Public UserOutputChannel As Byte
  298. Public SystemBytesToBeSentAvailable As Boolean = False
  299. Public SystemBytesToBeSent() As Byte
  300. Public SystemOutputChannel As Byte
  301. Public theClient As TcpClient
  302. Public IsRunning As Boolean = False
  303. Public remoteIpAddress As System.Net.IPAddress
  304. Public bytesRecieved() As Byte
  305. Public sessionID As Int32
  306. Public disConnect As Boolean = False
  307. Public bytesSentThisSecond As Int32 = 0
  308. Public bytesRecievedThisSecond As Int32 = 0
  309. Public fileBytesRecieved As Int64 = 0
  310. Public filebytesSent As Int64 = 0
  311. Public SendingFile As Boolean = False
  312. Public FileBeingSentPath As String
  313. Public IncomingFileSize As Int64
  314. Public IncomingFileName As String
  315. Public ReceivingFile As Boolean = False
  316. Public sendPacketSize As Boolean = False
  317. Public fileReader As FileStream
  318. Public fileWriter As clsAsyncUnbuffWriter
  319. Public ReceivedFilesFolder As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\ServerReceivedFiles"
  320. Public userName As String
  321. Public password As String
  322. Public paused As Boolean
  323. Public pauseSent As Boolean
  324. Public sendQueue As ConcurrentQueue(Of message)
  325. Public messageIn As MessageInQueue
  326. Public machineId As String
  327. Public class MessageInQueue
  328. Public queue As New ConcurrentQueue(Of message)
  329. Private bgThread As New Threading.Thread(AddressOf Pump)
  330. Private running As Boolean
  331. Private callBack As ServerCallbackDelegate
  332. Public Sub New(ByRef _callBack As ServerCallbackDelegate)
  333. callBack = _callBack
  334. running = True
  335. bgThread.IsBackground = True
  336. bgThread.Start()
  337. End Sub
  338. Public Sub Close()
  339. running = False
  340. End Sub
  341. Private Sub Pump()
  342. Dim lastSuccessfullPump as New Date
  343. Dim msg As message = Nothing
  344. While running
  345. If queue.TryDequeue(msg) then
  346. callBack(msg.bytes, msg.sessionID, msg.dataChannel)
  347. lastSuccessfullPump = Now
  348. End If
  349. If Now > lastSuccessfullPump.AddMilliseconds(5) then Thread.Sleep(1)
  350. End While
  351. End Sub
  352. End Class
  353. Public Sub New(ByVal _theClient As TcpClient, ByVal _sessionID As Int32)
  354. theClient = _theClient
  355. sessionID = _sessionID
  356. paused = False
  357. pauseSent = False
  358. End Sub
  359. Public Sub Close(Optional ByVal wait As Int32 = 500)
  360. Dim bgThread As New Thread(AddressOf WaitClose)
  361. bgThread.Start(wait)
  362. End Sub
  363. Private Sub WaitClose(ByVal waitmilliseconds As Object)
  364. Dim wait As Int32 = CType(waitmilliseconds, Int32)
  365. Thread.Sleep(wait)
  366. disConnect = True
  367. End Sub
  368. End Class
  369. Private SessionCollection As New Sessions
  370. Private SessionCollectionLocker As New Object
  371. ''' <summary>
  372. ''' Returns a current copy of the server's internal list of sessions as a List(Of SessionCommunications). It is possible that some sessions may be inactive,
  373. ''' or disconnected. Care should be taken to check the session.isRunning before using one,
  374. ''' because inactive or disconnected sessions may be overwritten by new connections at any moment.
  375. ''' </summary>
  376. ''' <returns>List(Of SessionCommunications)</returns>
  377. ''' <remarks></remarks>
  378. Public Function GetSessionCollection() As List(Of SessionCommunications)
  379. Dim thisCollection As List(Of SessionCommunications) = SessionCollection.GetSessionCollection()
  380. Return thisCollection
  381. End Function
  382. ''' <summary>
  383. ''' Gets the session object associated with the sessionId. Returns Nothing for sessions where session.isRunning = False.
  384. ''' </summary>
  385. ''' <param name="sessionId"></param>
  386. ''' <returns>A TcpComm.Server.SessionCommunications object</returns>
  387. ''' <remarks></remarks>
  388. Public Function GetSession(ByVal sessionId As Int32) As SessionCommunications
  389. Dim theSession As SessionCommunications = Nothing
  390. ' Sessions that are not running are not returned, so that they're sendqueues are not
  391. ' accidently inflated.
  392. If SessionCollection.GetSession(sessionId, theSession) then Return theSession
  393. Return Nothing
  394. End Function
  395. ''' <summary>
  396. ''' Gets the first session object associated with the MachineID. Returns Nothing for sessions where session.isRunning = False.
  397. ''' </summary>
  398. ''' <param name="aMachineID"></param>
  399. ''' <returns>A TcpComm.Server.SessionCommunications object</returns>
  400. ''' <remarks></remarks>
  401. Public Function GetSession(ByVal aMachineID As String) As SessionCommunications
  402. GetSession = Nothing
  403. SessionCollection.GetSession(aMachineID, GetSession)
  404. Return GetSession
  405. End Function
  406. ' CallbackForm must implement an UpdateUI Sub.
  407. Public Sub New(ByVal callbackMethod As ServerCallbackDelegate, Optional ByVal _throttledBytesPerSecond As UInt32 = 9000000)
  408. Mbps = _throttledBytesPerSecond
  409. ' BlockSize should be 62500 or 63100, depending on requested speed.
  410. ' Excellent performance, and works great with throttling.
  411. Dim _blockSize As UInt16
  412. ' Get corrected blocksize for throttling.
  413. If Mbps < 300000 Then
  414. If Mbps > 16000 Then
  415. blockSize = 4000
  416. Else
  417. blockSize = CUShort((Mbps / 4))
  418. End If
  419. ElseIf Mbps > 300000 And Mbps < 500000 Then
  420. blockSize = 16000
  421. ElseIf Mbps > 500000 And Mbps < 1000000 Then
  422. blockSize = 32000
  423. Else
  424. Dim count As UInt32 = 0
  425. Dim aFourth As Decimal = 0
  426. If Mbps > 25000000 Then
  427. _blockSize = 63100
  428. Else
  429. _blockSize = 62500
  430. End If
  431. aFourth = CDec(Mbps / 4)
  432. Do
  433. count += _blockSize
  434. If (count + _blockSize) > aFourth Then
  435. Mbps = CUInt(count * 4)
  436. blockSize = _blockSize
  437. Exit Do
  438. End If
  439. Loop
  440. End If
  441. ' Initialize the delegate object to point to the user's callback method.
  442. ServerCallbackObject = callbackMethod
  443. End Sub
  444. Public Sub ThrottleNetworkBps(ByVal bytesPerSecond As UInteger)
  445. ' Default value is 9000000 Mbps. Ok throughput, and
  446. ' good performance for the server (low CPU usage).
  447. Mbps = bytesPerSecond
  448. End Sub
  449. ''' <summary>
  450. ''' This is a convienience function that handles the work of converting the text you would like to send to a byte array.
  451. ''' Passes back the return value and errMsg of SendBytes(). Returns True on success and False on falure. Check the errMsg
  452. ''' string for send failure explanations.
  453. ''' </summary>
  454. ''' <param name="textMessage"></param>
  455. ''' <param name="channel"></param>
  456. ''' <param name="sessionid"></param>
  457. ''' <param name="errMsg"></param>
  458. ''' <returns></returns>
  459. ''' <remarks></remarks>
  460. Public Function SendText(ByVal textMessage As String, Optional ByVal channel As Byte = 1, Optional ByVal sessionid As Int32 = -1, _
  461. Optional ByRef errMsg As String = "") As Boolean
  462. If textMessage = "" then
  463. errMsg = "Your text message must contain some text."
  464. Return False
  465. End If
  466. Return SendBytes(StrToByteArray(textMessage), channel , sessionid, errMsg)
  467. End Function
  468. Public Function Start(ByVal prt As Integer, Optional ByRef errorMessage As String = "") As Boolean
  469. If serverState = currentState.running then
  470. errorMessage = "The server is already running."
  471. Return False
  472. End If
  473. serverState = currentState.idle
  474. Dim listenerThread As New Thread(AddressOf theListener)
  475. Try
  476. Port = prt
  477. localAddr = GetLocalIpAddress()
  478. continue_running = True
  479. IsRunning = True
  480. listenerThread.Name = "Server Listener Thread"
  481. listenerThread.Start()
  482. Catch ex As Exception
  483. errorMessage = ex.Message
  484. Return False
  485. End Try
  486. While serverState <> currentState.running
  487. Thread.Sleep(10)
  488. If serverState = currentState.err Or serverState = currentState.stopped Then
  489. errorMessage = errMsg
  490. Return False
  491. End If
  492. End While
  493. Return True
  494. End Function
  495. Public Sub Close()
  496. continue_running = False
  497. Try
  498. Listener.Stop()
  499. Catch ex As Exception
  500. End Try
  501. Try
  502. SessionCollection.ShutDown()
  503. Catch ex As Exception
  504. End Try
  505. IsRunning = False
  506. ServerCallbackObject(StrToByteArray("Server Stopped."), -1, 255)
  507. serverState = currentState.stopped
  508. End Sub
  509. Private Function GetLocalIpAddress() As System.Net.IPAddress
  510. Dim strHostName As String
  511. Dim addresses() As System.Net.IPAddress
  512. strHostName = System.Net.Dns.GetHostName()
  513. addresses = System.Net.Dns.GetHostAddresses(strHostName)
  514. ' Find an IpV4 address
  515. For Each address As System.Net.IPAddress In addresses
  516. ' Return the first IpV4 IP Address we find in the list.
  517. If address.AddressFamily = AddressFamily.InterNetwork Then
  518. Return address
  519. End If
  520. Next
  521. ' No IpV4 address? Return the loopback address.
  522. Return System.Net.IPAddress.Loopback
  523. End Function
  524. Public Function GetBlocksize() As UInt16
  525. Return blockSize
  526. End Function
  527. ''' <summary>
  528. ''' Returns the size of the selected session's sendqueue. Returns -1 if the session is nothing, or session.isRunning = False.
  529. ''' CAUTION: Calling this function too often will result in decreased performance, and failing to call it at all may result
  530. ''' in an out of memory error. You can continue to add messages to a session's send queue for as long as the session is active
  531. ''' (isRunning = True), but that doesn't mean they are being sent as fast as you are adding them to the queue (or at all, for that matter).
  532. ''' </summary>
  533. ''' <param name="sessionId"></param>
  534. ''' <returns>An Int32</returns>
  535. ''' <remarks></remarks>
  536. Public Function GetSendQueueSize(ByVal sessionId As Int32) As Int32
  537. Dim sendQueueSize As Int32 = -1
  538. Dim session As SessionCommunications = Nothing
  539. If SessionCollection.GetSession(sessionId, session) Then
  540. If session IsNot Nothing AndAlso session.IsRunning Then
  541. GetSendQueueSize = session.sendQueue.Count
  542. End If
  543. End If
  544. Return sendQueueSize
  545. End Function
  546. Public Function GetFile(ByVal _path As String, ByVal sessionID As Int32) As Boolean
  547. Dim thisSession As SessionCommunications = Nothing
  548. If SessionCollection.GetSession(sessionID, thisSession) then
  549. If thisSession is Nothing then Return False
  550. If Not thisSession.IsRunning then Return False
  551. thisSession.sendQueue.Enqueue(New message With { _
  552. .bytes = StrToByteArray("GFR:" & _path),
  553. .sessionID = sessionID,
  554. .dataChannel = 254
  555. })
  556. Else
  557. Return False
  558. End If
  559. End Function
  560. Public Function SendFile(ByVal _path As String, ByVal sessionID As Int32) As Boolean
  561. Dim thisSession As SessionCommunications = Nothing
  562. If SessionCollection.GetSession(sessionID, thisSession) then
  563. If thisSession is Nothing then Return False
  564. If Not thisSession.IsRunning then Return False
  565. thisSession.sendQueue.Enqueue(New message With { _
  566. .bytes = StrToByteArray("SFR:" & _path),
  567. .sessionID = sessionID,
  568. .dataChannel = 254
  569. })
  570. Else
  571. Return False
  572. End If
  573. Return True
  574. End Function
  575. Public Function SendBytes(ByVal bytes() As Byte, Optional ByVal channel As Byte = 1, Optional ByVal sessionID As Int32 = -1, _
  576. Optional ByRef errMsg As String = "") As Boolean
  577. Dim foundSession As Boolean = False
  578. If channel = 0 Or channel > 250 Then
  579. errMsg = "Data can not be sent using channel numbers less then 1 or greater then 250."
  580. Return False
  581. End If
  582. If sessionID > -1 then
  583. Dim targetSession As SessionCommunications = Nothing
  584. If SessionCollection.GetSession(sessionID, targetSession) then
  585. targetSession.sendQueue.Enqueue(New message With { _
  586. .bytes = bytes,
  587. .dataChannel = channel,
  588. .sessionID = sessionID
  589. })
  590. Return True
  591. End If
  592. Else
  593. SessionCollection.Broadcast(New message With { _
  594. .bytes = bytes,
  595. .dataChannel = channel,
  596. .sessionID = sessionID
  597. })
  598. Return True
  599. End If
  600. errMsg = "The session you are trying to write to is no longer available."
  601. Return False
  602. End Function
  603. Private Function RcvBytes(ByVal data() As Byte, ByVal session As SessionCommunications, Optional ByVal dataChannel As Byte = 1) As Boolean
  604. ' dataType: >0 = data channel, > 250 = internal messages. 0 is an invalid channel number (it's the puck)
  605. If dataChannel < 1 Then
  606. RcvBytes = False
  607. Exit Function
  608. End If
  609. Try
  610. ' Check to see if our app is closing
  611. If Not continue_running Then Exit Function
  612. Dim passedData(data.Length - 1) As Byte
  613. Array.Copy(data,passedData, data.Length)
  614. If session.sessionID > -1 then
  615. session.messageIn.queue.Enqueue(New message With { _
  616. .bytes = passedData,
  617. .dataChannel = dataChannel,
  618. .sessionID = session.sessionID
  619. })
  620. Else
  621. ' These are internal system messages. There is no session associated with them
  622. ServerCallbackObject(data, session.sessionID, dataChannel)
  623. End If
  624. Catch ex As Exception
  625. RcvBytes = False
  626. ' An unexpected error.
  627. Debug.WriteLine("Unexpected error in server\RcvBytes: " & ex.Message)
  628. End Try
  629. End Function
  630. Private Function SendExternalSystemMessage(ByVal message As String, ByVal session As SessionCommunications) As Boolean
  631. session.SystemBytesToBeSent = StrToByteArray(message)
  632. session.SystemOutputChannel = 254 ' Text messages / commands on channel 254
  633. session.SystemBytesToBeSentAvailable = True
  634. End Function
  635. Private Function CheckSessionPermissions(ByVal session As SessionCommunications, ByVal cmd As String) As Boolean
  636. ' Your security code here...
  637. Return True
  638. End Function
  639. Private Function BeginFileSend(ByVal _path As String, ByVal session As SessionCommunications, ByVal fileLength As Long) As Boolean
  640. Try
  641. session.fileReader = New FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.None, clsAsyncUnbuffWriter.GetPageSize)
  642. session.SendingFile = True
  643. BeginFileSend = True
  644. Catch ex As Exception
  645. BeginFileSend = False
  646. _path = ex.Message
  647. session.SendingFile = False
  648. End Try
  649. Try
  650. If Not BeginFileSend Then session.fileReader.Close()
  651. Catch ex As Exception
  652. End Try
  653. End Function
  654. Private Sub GetMoreFileBytesIfAvailable(ByVal session As SessionCommunications)
  655. Dim bytesRead As Int32 = 0
  656. If session.SendingFile And Not session.SystemBytesToBeSentAvailable Then
  657. Try
  658. If session.SystemBytesToBeSent.Length <> blockSize Then ReDim session.SystemBytesToBeSent(blockSize - 1)
  659. bytesRead = session.fileReader.Read(session.SystemBytesToBeSent, 0, blockSize)
  660. If bytesRead <> blockSize Then ReDim Preserve session.SystemBytesToBeSent(bytesRead - 1)
  661. If bytesRead > 0 Then
  662. session.SystemOutputChannel = 253 ' File transfer from server to client
  663. session.SystemBytesToBeSentAvailable = True
  664. Else
  665. ReDim session.SystemBytesToBeSent(blockSize - 1)
  666. SendExternalSystemMessage("->Done", session) ' Send the client a completion notice.
  667. session.SendingFile = False
  668. ' Clean up
  669. session.fileReader.Close()
  670. session.fileReader = Nothing
  671. GC.GetTotalMemory(True)
  672. End If
  673. Catch ex As Exception
  674. SendExternalSystemMessage("ERR: " & ex.Message, session)
  675. ' We're finished.
  676. ReDim session.SystemBytesToBeSent(blockSize - 1)
  677. session.SendingFile = False
  678. session.fileReader.Close()
  679. End Try
  680. End If
  681. End Sub
  682. Private Function GetFilenameFromPath(ByRef filePath As String) As String
  683. Dim filePathParts() As String
  684. If filePath.Trim = "" Then Return ""
  685. Try
  686. filePathParts = Split(filePath, "\")
  687. GetFilenameFromPath = filePathParts(filePathParts.Length - 1)
  688. Catch ex As Exception
  689. filePath = ex.Message
  690. Return ""
  691. End Try
  692. End Function
  693. Private Function CreateFolders(ByVal _path As String) As Boolean
  694. CreateFolders = True
  695. Dim parts() As String
  696. Dim path As String = ""
  697. Dim count As Int32
  698. parts = Split(_path, "\")
  699. path = parts(0)
  700. For count = 1 To parts.Length - 2
  701. path += "\" & parts(count)
  702. Try
  703. If Not Directory.Exists(path) Then
  704. Directory.CreateDirectory(path)
  705. End If
  706. Catch ex As Exception
  707. End Try
  708. Next
  709. End Function
  710. Private Function BeginToReceiveAFile(ByVal _path As String, ByVal session As SessionCommunications) As Boolean
  711. Dim readBuffer As Int32 = 0
  712. session.ReceivingFile = True
  713. BeginToReceiveAFile = True
  714. session.fileBytesRecieved = 0
  715. Try
  716. CreateFolders(_path) ' Just a 256k write buffer for the server. Let's try to avoid memory problems...
  717. session.fileWriter = New clsAsyncUnbuffWriter(_path, True, 1024 * 256, session.IncomingFileSize)
  718. Catch ex As Exception
  719. _path = ex.Message
  720. session.ReceivingFile = False
  721. End Try
  722. If Not session.ReceivingFile Then
  723. Try
  724. session.fileWriter.Close()
  725. Catch ex As Exception
  726. End Try
  727. Return False
  728. End If
  729. End Function
  730. Private Function HandleIncomingFileBytes(ByRef bytes() As Byte, ByVal session As SessionCommunications) As Boolean
  731. Try
  732. session.fileWriter.Write(bytes, bytes.Length)
  733. HandleIncomingFileBytes = True
  734. Catch ex As Exception
  735. HandleIncomingFileBytes = False
  736. End Try
  737. End Function
  738. Private Sub FinishReceivingTheFile(ByVal session As SessionCommunications)
  739. Try
  740. session.fileWriter.Close()
  741. session.fileWriter = Nothing
  742. session.ReceivingFile = False
  743. Catch ex As Exception
  744. session.ReceivingFile = False
  745. End Try
  746. End Sub
  747. Private Sub HandleIncomingSystemMessages(ByVal bytes() As Byte, ByVal channel As Byte, ByVal session As SessionCommunications)
  748. If channel = 254 Then ' Text commands / messages passed between server and client
  749. Dim message As String = BytesToString(bytes)
  750. Dim filePath As String
  751. Dim tmp As String = ""
  752. ' Get File Request: The client wants us to send them a file.
  753. If message.Length > 4 Then tmp = message.Substring(0, 4)
  754. If tmp = "GFR:" Then
  755. ' Get file path...
  756. filePath = message.Substring(4, message.Length - 4)
  757. ' Does it exist?
  758. If File.Exists(filePath) Then
  759. ' Do they have permission to get this file?
  760. If CheckSessionPermissions(session, "GFR") Then
  761. ' Are we already busy sending them a file?
  762. If Not session.SendingFile Then
  763. Dim _theFilesInfo As New FileInfo(filePath)
  764. If BeginFileSend(filePath, session, _theFilesInfo.Length) Then
  765. ' Send only the file NAME. It will have a different path on the other side.
  766. SendExternalSystemMessage("Sending:" & GetFilenameFromPath(filePath) & _
  767. ":" & _theFilesInfo.Length, session)
  768. Else
  769. ' FilePath contains the error message.
  770. SendExternalSystemMessage("ERR: " & filePath, session)
  771. End If
  772. Else
  773. ' There's already a GFR in progress.
  774. SendExternalSystemMessage("ERR: File: ''" & _
  775. session.FileBeingSentPath & _
  776. "'' is still in progress. Only one file " & _
  777. "may be transfered (from server to client) at a time.", session)
  778. End If
  779. Else
  780. ' This user doesn't have rights to "get" this file. Send an error.
  781. SendExternalSystemMessage("ERR: You do not have permission to receive files. Access Denied.", session)
  782. End If
  783. Else
  784. ' File doesn't exist. Send an error.
  785. SendExternalSystemMessage("ERR: The requested file can not be found by the server.", session)
  786. End If
  787. End If
  788. ' We're being informed that we will be receiving a file:
  789. If message.Length > 7 Then tmp = message.Substring(0, 8)
  790. If tmp = "Sending:" Then
  791. ' Strip away the headder...
  792. Dim msgParts() As String = Split(message, ":")
  793. session.IncomingFileSize = Convert.ToInt64(msgParts(2))
  794. session.IncomingFileName = msgParts(1)
  795. tmp = session.ReceivedFilesFolder & "\" & session.IncomingFileName
  796. SystemMessage("Receiving file: " & session.IncomingFileName)
  797. If Not BeginToReceiveAFile(tmp, session) Then
  798. SystemMessage("ERR: " & tmp)
  799. SendExternalSystemMessage("Abort->", session)
  800. End If
  801. End If
  802. If message.Length > 10 Then tmp = message.Substring(0, 10)
  803. If tmp = "MachineID:" Then
  804. message = message.Substring(10, message.Length - 10)
  805. session.machineId = message
  806. SystemMessage("Session#" & session.sessionID & " MachineID:" & session.machineId)
  807. End If
  808. If message = "<-Done" Then
  809. FinishReceivingTheFile(session)
  810. SystemMessage("<-Done")
  811. End If
  812. ' We've been notified that no file data will be forthcoming.
  813. If message = "Abort<-" Then
  814. WrapUpIncomingFile(session)
  815. SystemMessage("<-Aborted.")
  816. SendExternalSystemMessage("<-Aborted.", session)
  817. End If
  818. ' Send File Request: The client wants to send us a file.
  819. If message.Length > 4 Then tmp = message.Substring(0, 4)
  820. If tmp = "SFR:" Then
  821. If CheckSessionPermissions(session, "SFR") Then
  822. Dim parts() As String
  823. parts = Split(message, "SFR:")
  824. SendExternalSystemMessage("GFR:" & parts(1), session)
  825. Else
  826. ' This user doesn't have rights to send us a file. Send an error.
  827. SendExternalSystemMessage("ERR: You do not have permission to send files. Access Denied.", session)
  828. End If
  829. End If
  830. If message.Length > 4 Then tmp = message.Substring(0, 4)
  831. If tmp = "GDR:" Then ' Get Directory Request
  832. ' Send each file in the directory and all subdirectories.
  833. ' To be implemented in the future.
  834. End If
  835. If message.Length > 4 Then tmp = message.Substring(0, 4)
  836. If tmp = "ERR:" Then ' The client has sent us an error message.
  837. ' Pass it on up to the user.
  838. SystemMessage(message)
  839. End If
  840. ' New queue throttling code
  841. If message = "pause" Then
  842. session.paused = True
  843. End If
  844. If message = "resume" Then
  845. session.paused = False
  846. End If
  847. If message = "Abort->" Then
  848. Try
  849. session.SendingFile = False
  850. ReDim session.SystemBytesToBeSent(blockSize - 1)
  851. SendExternalSystemMessage("->Aborted.", session)
  852. SystemMessage("->Aborted.")
  853. session.fileReader.Close()
  854. Catch ex As Exception
  855. End Try
  856. End If
  857. ' The client is disconnecting. Close the connection gracefully...
  858. If message = "close" Then
  859. ' This will be caught by the try in the run sub, and execution
  860. ' will drop out of the communication loop immediately and
  861. ' begin the shutdown process.
  862. Throw New Exception("Gracefull shutdown in progress.")
  863. End If
  864. ElseIf channel = 253 Then ' File transfer from server to client
  865. ElseIf channel = 252 Then ' File transfer from client to server
  866. Try
  867. If session.ReceivingFile Then
  868. HandleIncomingFileBytes(bytes, session)
  869. session.fileBytesRecieved += bytes.Length
  870. End If
  871. Catch ex As Exception
  872. End Try
  873. ElseIf channel = 251 Then ' reserved.
  874. End If
  875. End Sub
  876. Private Function HandleOutgoingInternalSystemMessage(ByVal Stream As NetworkStream, _
  877. ByVal session As SessionCommunications) As Boolean
  878. Dim tmp(1) As Byte
  879. Dim _size As UShort
  880. 'Static OurTurn As Boolean = False
  881. HandleOutgoingInternalSystemMessage = False
  882. ' Create a one time outgoing system message to syncronize packet size.
  883. If Not session.sendPacketSize Then
  884. SendExternalSystemMessage("blocksize:" & blockSize.ToString, session)
  885. session.sendPacketSize = True
  886. End If
  887. GetMoreFileBytesIfAvailable(session)
  888. ' Handle outgoing system stuff here
  889. If session.SystemBytesToBeSentAvailable = True Then
  890. HandleOutgoingInternalSystemMessage = True
  891. If session.SystemBytesToBeSent.Length > blockSize Then
  892. ' Send Channel
  893. tmp(0) = session.SystemOutputChannel
  894. Stream.Write(tmp, 0, 1)
  895. ' Send packet size
  896. _size = blockSize
  897. tmp = BitConverter.GetBytes(_size)
  898. Stream.Write(tmp, 0, 2)
  899. ' Send packet
  900. Stream.Write(GetSome(session.SystemBytesToBeSent, blockSize, session.SystemBytesToBeSentAvailable, session), 0, _size)
  901. session.bytesSentThisSecond += 3 + blockSize
  902. Else
  903. ' Send Channel
  904. tmp(0) = session.SystemOutputChannel
  905. Stream.Write(tmp, 0, 1)
  906. ' Send packet size
  907. _size = Convert.ToUInt16(session.SystemBytesToBeSent.Length)
  908. tmp = BitConverter.GetBytes(_size)
  909. Stream.Write(tmp, 0, 2)
  910. ' Send packet
  911. Stream.Write(session.SystemBytesToBeSent, 0, _size)
  912. session.bytesSentThisSecond += 3 + _size
  913. session.SystemBytesToBeSentAvailable = False
  914. End If
  915. End If
  916. End Function
  917. Private Function HandleOutgoingUserData(ByVal Stream As NetworkStream, ByVal session As SessionCommunications) As Boolean
  918. Dim tmp(1) As Byte
  919. Dim _size As UShort
  920. Dim notify As Boolean = False
  921. Static packet(0) As Byte
  922. Dim msg As message = Nothing
  923. Dim shutSessionDown As Boolean = False
  924. If Not session.UserBytesToBeSentAvailable then
  925. If session.sendQueue.TryDequeue(msg) then
  926. session.UserBytesToBeSentAvailable = True
  927. session.UserBytesToBeSent = New MemoryStream(msg.bytes)
  928. session.UserOutputChannel = msg.dataChannel
  929. End If
  930. End If
  931. If session.disConnect Then
  932. session.UserBytesToBeSentAvailable = True
  933. session.UserBytesToBeSent = New MemoryStream(StrToByteArray("close"))
  934. session.UserOutputChannel = 254
  935. shutSessionDown = True
  936. End If
  937. If session.UserBytesToBeSentAvailable = True Then
  938. Try
  939. If (session.UserBytesToBeSent.Length - session.UserBytesToBeSent.Position) > blockSize Then
  940. ' Send Channel
  941. tmp(0) = session.UserOutputChannel
  942. Stream.Write(tmp, 0, 1)
  943. ' Send packet size
  944. _size = blockSize
  945. tmp = BitConverter.GetBytes(_size)
  946. Stream.Write(tmp, 0, 2)
  947. ' Send packet
  948. If packet.Length <> _size Then ReDim packet(_size - 1)
  949. session.UserBytesToBeSent.Read(packet, 0, _size)
  950. 'session.theClient.NoDelay = True
  951. Stream.Write(packet, 0, _size)
  952. session.bytesSentThisSecond += 3 + _size
  953. ' Check to see if we've sent it all...
  954. If session.UserBytesToBeSent.Length = session.UserBytesToBeSent.Position Then
  955. session.UserBytesToBeSentAvailable = False
  956. notify = True
  957. End If
  958. Else
  959. ' Send Channel
  960. tmp(0) = session.UserOutputChannel
  961. Stream.Write(tmp, 0, 1)
  962. ' Send packet size
  963. _size = Convert.ToUInt16(session.UserBytesToBeSent.Length - session.UserBytesToBeSent.Position)
  964. tmp = BitConverter.GetBytes(_size)
  965. Stream.Write(tmp, 0, 2)
  966. ' Send packet
  967. If packet.Length <> _size Then ReDim packet(_size - 1)
  968. session.UserBytesToBeSent.Read(packet, 0, _size)
  969. 'session.theClient.NoDelay = True
  970. Stream.Write(packet, 0, _size)
  971. session.bytesSentThisSecond += 3 + _size
  972. session.UserBytesToBeSentAvailable = False
  973. notify = True
  974. End If
  975. Catch ex As Exception
  976. ' Report error attempting to send user data.
  977. Debug.WriteLine("Unexpected error in TcpCommServer\HandleOutgoingUserData: " & ex.Message)
  978. End Try
  979. ' Notify the user that the packet has been sent.
  980. If notify Then SystemMessage("UBS:" & session.sessionID & ":" & session.UserOutputChannel)
  981. ' This will drop execution out of the communications loop for this session, and
  982. ' begin this session's shutdown process.
  983. If shutSessionDown then Throw New Exception("Shutting session down gracefully.")
  984. Return True
  985. Else
  986. Return False
  987. End If
  988. End Function
  989. Private Function GetSome(ByRef bytes() As Byte, ByVal chunkToBreakOff As Integer, _
  990. ByRef bytesToBeSentAvailable As Boolean, ByVal session As SessionCommunications, _
  991. Optional ByVal theseAreUserBytes As Boolean = False) As Byte()
  992. Dim tmp(chunkToBreakOff - 1) As Byte
  993. Array.Copy(bytes, 0, tmp, 0, chunkToBreakOff)
  994. GetSome = tmp
  995. If bytes.Length = chunkToBreakOff Then
  996. bytesToBeSentAvailable = False
  997. If theseAreUserBytes Then SystemMessage("UBS:" & session.sessionID & ":" & session.UserOutputChannel)
  998. Else
  999. Dim tmp2(bytes.Length - chunkToBreakOff - 1) As Byte
  1000. Array.Copy(bytes, chunkToBreakOff, tmp2, 0, bytes.Length - chunkToBreakOff)
  1001. bytes = tmp2
  1002. End If
  1003. End Function
  1004. Private Sub SystemMessage(ByVal MsgText As String)
  1005. Dim bgMsg As New Thread(AddressOf BgMessage)
  1006. bgMsg.IsBackground = True
  1007. bgMsg.Start(MsgText)
  1008. End Sub
  1009. Private Sub BgMessage(ByVal _text As Object)
  1010. Dim msg As String = CType(_text, String)
  1011. RcvBytes(StrToByteArray(msg), New SessionCommunications(New TcpClient, -1), 255)
  1012. End Sub
  1013. Private Sub SystemMessage(ByVal MsgText As String, ByVal sessionId As Int32)
  1014. RcvBytes(StrToByteArray(MsgText), New SessionCommunications(New TcpClient, sessionId), 255)
  1015. End Sub
  1016. ' Check to see if our app is closing (set in FormClosing event)
  1017. Private Function theServerIsStopping(ByVal Server As TcpClient, ByVal session As SessionCommunications) As Boolean
  1018. If Not continue_running Or session.disConnect Then
  1019. theServerIsStopping = True
  1020. Else
  1021. theServerIsStopping = False
  1022. End If
  1023. End Function
  1024. Private Sub theListener()
  1025. Try
  1026. ' Start listening
  1027. SystemMessage("Listening...")
  1028. Listener = New TcpListener(localAddr, Port)
  1029. Listener.Start()
  1030. StartAccept()
  1031. Catch ex As Exception
  1032. errMsg = ex.Message
  1033. serverState = currentState.err
  1034. Exit Sub
  1035. End Try
  1036. serverState = currentState.running
  1037. End Sub
  1038. Private Function StartAccept() As Boolean
  1039. Try
  1040. Listener.BeginAcceptTcpClient(AddressOf HandleAsyncConnection, Listener)
  1041. Return True
  1042. Catch ex As Exception
  1043. Return False
  1044. End Try
  1045. End Function
  1046. Private Sub HandleAsyncConnection(ByVal res As IAsyncResult)
  1047. Dim client As TcpClient
  1048. If Not StartAccept() Then Exit Sub
  1049. client = Listener.EndAcceptTcpClient(res)
  1050. Dim thisTask = System.Threading.Tasks.Task.Factory
  1051. thisTask.StartNew(Sub()
  1052. HandleNewConnection(client)
  1053. End Sub)
  1054. End Sub
  1055. Private sessionIdIncrementLock As New Object
  1056. Private Sub HandleNewConnection(ByVal client As TcpClient)
  1057. Dim thisSessionId As Int32 = -1
  1058. Dim session As SessionCommunications
  1059. thisSessionId = SessionCollection.GetReusableSessionID
  1060. If thisSessionId = -1 then
  1061. SyncLock sessionIdIncrementLock
  1062. thisSessionId = newSessionId
  1063. newSessionId += 1
  1064. End SyncLock
  1065. End If
  1066. Dim newSession As New Thread(AddressOf Run)
  1067. session = New SessionCommunications(client, thisSessionId)
  1068. newSession.IsBackground = True
  1069. newSession.Name = "Server Session #" & thisSessionId
  1070. newSession.Start(session)
  1071. SessionCollection.AddSession(session)
  1072. 'SystemMessage("Connected.")
  1073. End Sub
  1074. Private Sub WrapUpIncomingFile(ByVal session As SessionCommunications)
  1075. If session.ReceivingFile Then
  1076. Try
  1077. session.fileWriter.Close()
  1078. session.fileWriter = Nothing
  1079. GC.GetTotalMemory(True)
  1080. Catch ex As Exception
  1081. End Try
  1082. Try
  1083. File.Delete(session.ReceivedFilesFolder & "\" & session.IncomingFileName)
  1084. Catch ex As Exception
  1085. End Try
  1086. End If
  1087. End Sub
  1088. Private Sub Run(ByVal _session As Object)
  1089. Dim session As SessionCommunications = DirectCast(_session, SessionCommunications)
  1090. session.sendQueue = New ConcurrentQueue(Of message)
  1091. session.messageIn = New SessionCommunications.MessageInQueue(ServerCallbackObject)
  1092. Dim Server As TcpClient
  1093. Dim Stream As NetworkStream
  1094. Dim IpEndPoint As IPEndPoint
  1095. Dim puck(1) As Byte : puck(0) = 0
  1096. Dim theBuffer(blockSize - 1) As Byte
  1097. Dim tmp(1) As Byte
  1098. Dim dataChannel As Byte = 0
  1099. Dim packetSize As UShort = 0
  1100. Dim idleTimer, bandwidthTimer As Date
  1101. Dim bytesread As Integer = 0
  1102. Dim weHaveThePuck As Boolean = True
  1103. Dim bandwidthUsedThisSecond As Int32 = 0
  1104. Dim userOrSystemSwitcher As Integer = 0
  1105. Try
  1106. ' Create a local Server and Stream objects for clarity.
  1107. Server = session.theClient
  1108. Stream = Server.GetStream()
  1109. Catch ex As Exception
  1110. ' An unexpected error.
  1111. Debug.WriteLine("Could not create local Server or Stream object in server. Message: " & ex.Message)
  1112. Exit Sub
  1113. End Try
  1114. Try
  1115. ' Get the remote machine's IP address.
  1116. IpEndPoint = CType(Server.Client.RemoteEndPoint, Net.IPEndPoint)
  1117. session.remoteIpAddress = IpEndPoint.Address
  1118. ' Set the send and receive buffers to the maximum
  1119. ' size allowable in this application...
  1120. Server.Client.ReceiveBufferSize = 65535
  1121. Server.Client.SendBufferSize = 65535
  1122. ' no delay on partially filled packets...
  1123. ' Send it all as fast as possible.
  1124. Server.NoDelay = True
  1125. ' Set the timers...
  1126. idleTimer = Now
  1127. bandwidthTimer = Now
  1128. session.IsRunning = True
  1129. SystemMessage("Connected.")
  1130. ' Start the communication loop
  1131. Do
  1132. ' Throttle network Mbps...
  1133. bandwidthUsedThisSecond = session.bytesSentThisSecond + session.bytesRecievedThisSecond
  1134. If bandwidthTimer.AddMilliseconds(250) >= Now And bandwidthUsedThisSecond >= (Mbps / 4) Then
  1135. While bandwidthTimer.AddMilliseconds(250) > Now
  1136. Thread.Sleep(0)
  1137. End While
  1138. End If
  1139. If bandwidthTimer.AddMilliseconds(250) <= Now Then
  1140. bandwidthTimer = Now
  1141. session.bytesRecievedThisSecond = 0
  1142. session.bytesSentThisSecond = 0
  1143. bandwidthUsedThisSecond = 0
  1144. End If
  1145. ' Normal communications...
  1146. If weHaveThePuck Then
  1147. ' Send data if there is any to be sent...
  1148. userOrSystemSwitcher += 1
  1149. Select Case userOrSystemSwitcher
  1150. Case 1
  1151. If Not session.paused Then
  1152. If HandleOutgoingUserData(Stream, session) Then idleTimer = Now
  1153. End If
  1154. Case 2
  1155. If HandleOutgoingInternalSystemMessage(Stream, session) Then idleTimer = Now
  1156. End Select
  1157. If userOrSystemSwitcher > 1 Then userOrSystemSwitcher = 0
  1158. ' After sending out data, send the puck
  1159. Stream.Write(puck, 0, 1)
  1160. weHaveThePuck = False
  1161. End If
  1162. If theBuffer.Length < 2 Then ReDim theBuffer(1)
  1163. ' Read in the control byte.
  1164. Stream.Read(theBuffer, 0, 1)
  1165. dataChannel = theBuffer(0)
  1166. ' If it's just the puck (communictaion syncronization byte),
  1167. ' set weHaveThePuck true, record the byte read for throttling,
  1168. ' and that's all. dataChannel 0 is reserved for the puck.
  1169. If dataChannel = 0 Then
  1170. weHaveThePuck = True
  1171. session.bytesRecievedThisSecond += 1
  1172. Else
  1173. ' It's not the puck: It's an incoming packet.
  1174. ' Get the packet size:
  1175. tmp(0) = Convert.ToByte(Stream.ReadByte)
  1176. tmp(1) = Convert.ToByte(Stream.ReadByte)
  1177. packetSize = BitConverter.ToUInt16(tmp, 0)
  1178. session.bytesRecievedThisSecond += 2
  1179. ' Get the packet:
  1180. If theBuffer.Length <> packetSize Then ReDim theBuffer(packetSize - 1)
  1181. Do
  1182. ' Read bytes in...
  1183. bytesread += Stream.Read(theBuffer, bytesread, (packetSize - bytesread))
  1184. Loop While bytesread < packetSize
  1185. bytesread = 0
  1186. ' Record bytes read for throttling...
  1187. session.bytesRecievedThisSecond += packetSize
  1188. ' Handle the packet...
  1189. If dataChannel > 250 Then
  1190. ' this is an internal system packet
  1191. If Not theServerIsStopping(Server, session) Then HandleIncomingSystemMessages(theBuffer, dataChannel, session)
  1192. Else
  1193. ' Hand user data off to the calling thread.
  1194. If Not theServerIsStopping(Server, session) Then RcvBytes(theBuffer, session, dataChannel)
  1195. End If
  1196. idleTimer = Now
  1197. End If
  1198. ' Throttle CPU usage when idle.
  1199. If Now > idleTimer.AddMilliseconds(500) Then
  1200. Thread.Sleep(50)
  1201. End If
  1202. Loop
  1203. Catch ex As Exception
  1204. ' An unexpected error.
  1205. Debug.WriteLine("Unexpected error in server: " & ex.Message)
  1206. End Try
  1207. Try
  1208. session.fileReader.Close()
  1209. Catch ex As Exception
  1210. End Try
  1211. Try
  1212. Server.Client.Close()
  1213. Server.Client.Blocking = False
  1214. Catch ex As Exception
  1215. End Try
  1216. ' If we're in the middle of receiving a file,
  1217. ' close the filestream, release the memory and
  1218. ' delete the partial file.
  1219. WrapUpIncomingFile(session)
  1220. session.IsRunning = False
  1221. session.machineId = ""
  1222. SystemMessage("Session Stopped. (" & session.sessionID.ToString & ")")
  1223. session.messageIn.Close()
  1224. SessionCollection.ReuseSessionNumber(session.sessionID)
  1225. End Sub
  1226. End Class
  1227. Public Class Client
  1228. Public errMsg As String
  1229. ' Define the delegate type
  1230. Public Delegate Sub ClientCallbackDelegate(ByVal bytes() As Byte, ByVal dataChannel As Byte)
  1231. ' Create Delegate pointer
  1232. Public ClientCallbackObject As ClientCallbackDelegate
  1233. Private continue_running As Boolean = False
  1234. Private bytes() As Byte
  1235. Private blockSize As UInt16
  1236. Private IP As System.Net.IPAddress
  1237. Private Port As Integer
  1238. Private localAddr As IPAddress
  1239. Private Client As TcpClient
  1240. Private Stream As NetworkStream
  1241. Private fileWriter As clsAsyncUnbuffWriter
  1242. Private fileReader As FileStream
  1243. Private FileBeingSentPath As String
  1244. Private weHaveThePuck As Boolean = False
  1245. Private isRunning As Boolean = False
  1246. Private UserBytesToBeSentAvailable As Boolean = False
  1247. Private UserBytesToBeSent As New MemoryStream
  1248. Private UserOutputChannel As Byte
  1249. Private SystemBytesToBeSentAvailable As Boolean = False
  1250. Private SystemBytesToBeSent() As Byte
  1251. Private SystemOutputChannel As Byte
  1252. Private SendingFile As Boolean = False
  1253. Private ReceivingFile As Boolean = False
  1254. Private IncomingFileName As String
  1255. Private IncomingFileSize As Int64 = 0
  1256. Private outgoingFileSize As UInt64 = 0
  1257. Private outgoingFileName As String
  1258. Private fileBytesRecieved As Int64 = 0
  1259. Private filebytesSent As Int64 = 0
  1260. Private bytesSentThisSecond As Int32 = 0
  1261. Private bytesReceivedThisSecond As Int32 = 0
  1262. Private mbpsOneSecondAverage() As Int32
  1263. Private ReceivedFilesFolder As String = Application.StartupPath & "\ReceivedFiles"
  1264. Private userName As String
  1265. Private password As String
  1266. Private machineId As String
  1267. Private Class message
  1268. Public bytes() As Byte
  1269. Public dataChannel As Byte
  1270. End Class
  1271. Private class MessageInQueue
  1272. Public queue As New ConcurrentQueue(Of message)
  1273. Private bgThread As New Threading.Thread(AddressOf Pump)
  1274. Private running As Boolean
  1275. Private callBack As ClientCallbackDelegate
  1276. Public Sub New(ByRef _callBack As ClientCallbackDelegate)
  1277. callBack = _callBack
  1278. running = True
  1279. bgThread.Start()
  1280. End Sub
  1281. Public Sub Close()
  1282. running = False
  1283. End Sub
  1284. Private Sub Pump()
  1285. Dim lastSuccessfullPump as New Date
  1286. Dim msg As message = Nothing
  1287. While running
  1288. If queue.TryDequeue(msg) then
  1289. callBack(msg.bytes, msg.dataChannel)
  1290. lastSuccessfullPump = Now
  1291. End If
  1292. If Now > lastSuccessfullPump.AddMilliseconds(25) then Thread.Sleep(1)
  1293. End While
  1294. End Sub
  1295. End Class
  1296. Private sendQueue As ConcurrentQueue(Of message)
  1297. Private mbpsSyncObject As New AutoResetEvent(False)
  1298. Private messageIn As MessageInQueue
  1299. Public Function isClientRunning() As Boolean
  1300. Return isRunning
  1301. End Function
  1302. Public Function SetReceivedFilesFolder(ByVal _path As String) As Boolean
  1303. ReceivedFilesFolder = _path
  1304. End Function
  1305. Public Function GetIncomingFileName() As String
  1306. Return IncomingFileName
  1307. End Function
  1308. Public Function GetOutgoingFileName() As String
  1309. Return outgoingFileName
  1310. End Function
  1311. Public Function GetPercentOfFileReceived() As UInt16
  1312. If ReceivingFile Then
  1313. Return CUShort((fileBytesRecieved / IncomingFileSize) * 100)
  1314. Else
  1315. Return 0
  1316. End If
  1317. End Function
  1318. Public Function GetPercentOfFileSent() As UInt16
  1319. If SendingFile Then
  1320. Return CUShort((filebytesSent / outgoingFileSize) * 100)
  1321. Else
  1322. Return 0
  1323. End If
  1324. End Function
  1325. Public Function GetMbps() As String
  1326. Dim currentMbps As Decimal = CalculateMbps(True)
  1327. If currentMbps > 1000000 Then
  1328. Return (currentMbps / 1000000).ToString("N2") & " Mbps"
  1329. Else
  1330. Return (currentMbps / 1000).ToString("N2") & " Kbps"
  1331. End If
  1332. End Function
  1333. Public Function GetLocalIpAddress() As System.Net.IPAddress
  1334. Dim strHostName As String
  1335. Dim addresses() As System.Net.IPAddress
  1336. strHostName = System.Net.Dns.GetHostName()
  1337. addresses = System.Net.Dns.GetHostAddresses(strHostName)
  1338. ' Find an IpV4 address
  1339. For Each address As System.Net.IPAddress In addresses
  1340. ' Return the first IpV4 IP Address we find in the list.
  1341. If address.AddressFamily = AddressFamily.InterNetwork Then
  1342. Return address
  1343. End If
  1344. Next
  1345. ' No IpV4 address? Return the loopback address.
  1346. Return System.Net.IPAddress.Loopback
  1347. End Function
  1348. Private Function GetIPFromHostname(ByVal hostname As String, Optional returnLoopbackOnFail As Boolean = True) As System.Net.IPAddress
  1349. Dim addresses() As System.Net.IPAddress
  1350. Try
  1351. addresses = System.Net.Dns.GetHostAddresses(hostname)
  1352. Catch ex As Exception
  1353. If returnLoopbackOnFail Then Return System.Net.IPAddress.Loopback
  1354. Return Nothing
  1355. End Try
  1356. ' Find an IpV4 address
  1357. For Each address As System.Net.IPAddress In addresses
  1358. ' Return the first IpV4 IP Address we find in the list.
  1359. If address.AddressFamily = AddressFamily.InterNetwork Then
  1360. Return address
  1361. End If
  1362. Next
  1363. ' No IpV4 address? Return the loopback address.
  1364. If returnLoopbackOnFail Then Return System.Net.IPAddress.Loopback
  1365. Return Nothing
  1366. End Function
  1367. Public Sub New(ByRef callbackMethod As ClientCallbackDelegate)
  1368. blockSize = 10000
  1369. ' Initialize the delegate variable to point to the user's callback method.
  1370. ClientCallbackObject = callbackMethod
  1371. End Sub
  1372. Public Function Connect(ByVal IP_Address As String, ByVal prt As Integer, Optional newMachineID As String = "", _
  1373. Optional ByRef errorMessage As String = "") As Boolean
  1374. Try
  1375. ' Attempt to get the ip address by parsing the IP_Address string:
  1376. IP = System.Net.IPAddress.Parse(IP_Address)
  1377. Catch ex As Exception
  1378. ' We got an error - it's not an ip address.
  1379. ' Maybe it's a hostname.
  1380. IP = GetIPFromHostname(IP_Address, False)
  1381. End Try
  1382. If IP Is Nothing Then
  1383. ' Handle invalid IP address passed here.
  1384. errorMessage = "Could not connect to " & IP_Address & ". It is not a valid IP address or hostname on this network."
  1385. Return False
  1386. End If
  1387. Port = prt
  1388. continue_running = True
  1389. errMsg = ""
  1390. sendQueue = New ConcurrentQueue(Of message)
  1391. messageIn = New MessageInQueue(ClientCallbackObject)
  1392. Dim clientCommunicationThread As New Thread(AddressOf Run)
  1393. clientCommunicationThread.Name = "ClientCommunication"
  1394. clientCommunicationThread.Start()
  1395. If Not newMachineID.Equals("") then
  1396. SetMachineID(newMachineID)
  1397. End If
  1398. ' Wait for connection...
  1399. While Not isRunning And errMsg = ""
  1400. Thread.Sleep(5)
  1401. End While
  1402. ' Are we connected?
  1403. errorMessage = errMsg
  1404. If Not isRunning Then
  1405. messageIn.Close
  1406. Return False
  1407. End If
  1408. Return True
  1409. End Function
  1410. Public Sub Close()
  1411. continue_running = False
  1412. End Sub
  1413. Public Function GetBlocksize() As UInt16
  1414. Return blockSize
  1415. End Function
  1416. ''' <summary>
  1417. ''' Returns the size of the sendqueue. Returns -1 if isRunning = False.
  1418. ''' CAUTION: Calling this function too often will result in decreased performance, and failing to call it at all may result
  1419. ''' in an out of memory error. You can continue to add messages to the send queue for as long as the connection is active
  1420. ''' (isRunning = True), but that doesn't mean they are being sent as fast as you are adding them to the queue (or at all, for that matter).
  1421. ''' </summary>
  1422. ''' <returns>An Int32</returns>
  1423. ''' <remarks></remarks>
  1424. Public Function GetSendQueueSize() As Int32
  1425. Dim sendQueueSize As Int32 = -1
  1426. If isRunning then GetSendQueueSize = sendQueue.Count
  1427. Return sendQueueSize
  1428. End Function
  1429. Public Function GetFile(ByVal _path As String) As Boolean
  1430. sendQueue.Enqueue(New message With { _
  1431. .bytes = StrToByteArray("GFR:" & _path),
  1432. .dataChannel = 254
  1433. })
  1434. End Function
  1435. Public Function SendFile(ByVal _path As String) As Boolean
  1436. sendQueue.Enqueue(New message With { _
  1437. .bytes = StrToByteArray("SFR:" & _path),
  1438. .dataChannel = 254
  1439. })
  1440. End Function
  1441. Public Sub CancelIncomingFileTransfer()
  1442. sendQueue.Enqueue(New message With { _
  1443. .bytes = StrToByteArray("Abort->"),
  1444. .dataChannel = 254
  1445. })
  1446. FinishReceivingTheFile()
  1447. Dim killFileThread As New System.Threading.Thread(AddressOf KillIncomingFile)
  1448. killFileThread.Start(ReceivedFilesFolder & "\" & IncomingFileName)
  1449. End Sub
  1450. Private Sub KillIncomingFile(_path as Object)
  1451. Dim filePath As String = CType(_path, String)
  1452. Dim timeOut As New Stopwatch
  1453. timeOut.Start()
  1454. While timeOut.ElapsedMilliseconds < 1000
  1455. Try
  1456. If Not File.Exists(filePath) then Exit While
  1457. File.Delete(filePath)
  1458. Catch ex As Exception
  1459. End Try
  1460. End While
  1461. End Sub
  1462. Public Sub CancelOutgoingFileTransfer()
  1463. sendQueue.Enqueue(New message With { _
  1464. .bytes = StrToByteArray("Abort<-"),
  1465. .dataChannel = 254
  1466. })
  1467. StopSendingTheFile()
  1468. End Sub
  1469. Public Sub SetMachineID(ByVal id As String)
  1470. machineId = id
  1471. sendQueue.Enqueue(New message With { _
  1472. .bytes = StrToByteArray("MachineID:" & id),
  1473. .dataChannel = 254
  1474. })
  1475. End Sub
  1476. Public Function GetErrorMessage() As String
  1477. Return errMsg
  1478. End Function
  1479. Public Function SendBytes(ByVal bytes() As Byte, Optional ByVal channel As Byte = 1, Optional ByRef errMsg As String = "") As Boolean
  1480. If channel = 0 Or channel > 250 Then
  1481. errMsg = "Data can not be sent using channel numbers less then 1 or greater then 250."
  1482. Return False
  1483. End If
  1484. If bytes is Nothing or bytes.Length = 0 then
  1485. errMsg = "bytes() must contain more then 0 bytes, and not be nothing."
  1486. Return False
  1487. End If
  1488. sendQueue.Enqueue(New message With { _
  1489. .bytes = bytes,
  1490. .dataChannel = channel
  1491. })
  1492. Return True
  1493. End Function
  1494. ''' <summary>
  1495. ''' This is a convienience function that handles the work of converting the text you would like to send to a byte array.
  1496. ''' Passes back the return value and errMsg of SendBytes(). Returns True on success and False on falure. Check the errMsg
  1497. ''' string for send failure explanations.
  1498. ''' </summary>
  1499. ''' <param name="textMessage"></param>
  1500. ''' <param name="channel"></param>
  1501. ''' <param name="errMsg"></param>
  1502. ''' <returns></returns>
  1503. ''' <remarks></remarks>
  1504. Public Function SendText(ByVal textMessage As String, Optional ByVal channel As Byte = 1, _
  1505. Optional ByRef errMsg As String = "") As Boolean
  1506. If textMessage = "" then
  1507. errMsg = "Your text message must contain some text."
  1508. Return False
  1509. End If
  1510. Return SendBytes(StrToByteArray(textMessage), channel, errMsg)
  1511. End Function
  1512. Private Function RcvBytes(ByVal data() As Byte, Optional ByVal dataChannel As Byte = 1) As Boolean
  1513. ' dataType: >0 = data channel, 251 and up = internal messages. 0 is an invalid channel number (it's the puck)
  1514. If dataChannel < 1 Or Not continue_running Then Return False
  1515. Try
  1516. Dim passedData(data.Length - 1) As Byte
  1517. Array.Copy(data, passedData, data.Length)
  1518. messageIn.queue.Enqueue(New message With { _
  1519. .bytes = passedData,
  1520. .dataChannel = dataChannel
  1521. })
  1522. 'ClientCallbackObject(data, datachannel)
  1523. Catch ex As Exception
  1524. ' An unexpected error.
  1525. Debug.WriteLine("Unexpected error in Client\RcvBytes: " & ex.Message)
  1526. Return False
  1527. End Try
  1528. Return True
  1529. End Function
  1530. Private Function CreateFolders(ByVal _path As String) As Boolean
  1531. CreateFolders = True
  1532. Dim parts() As String
  1533. Dim path As String = ""
  1534. Dim count As Int32
  1535. parts = Split(_path, "\")
  1536. path = parts(0)
  1537. For count = 1 To parts.Length - 2
  1538. path += "\" & parts(count)
  1539. Try
  1540. If Not Directory.Exists(path) Then
  1541. Directory.CreateDirectory(path)
  1542. End If
  1543. Catch ex As Exception
  1544. End Try
  1545. Next
  1546. End Function
  1547. Private Function SendExternalSystemMessage(ByVal message As String) As Boolean
  1548. SystemBytesToBeSent = StrToByteArray(message)
  1549. SystemOutputChannel = 254 ' Text messages / commands on channel 254
  1550. SystemBytesToBeSentAvailable = True
  1551. End Function
  1552. Private Function BeginToReceiveAFile(ByVal _path As String) As Boolean
  1553. Dim readBuffer As Int32 = 0
  1554. ReceivingFile = True
  1555. BeginToReceiveAFile = True
  1556. fileBytesRecieved = 0
  1557. Try
  1558. CreateFolders(_path)
  1559. fileWriter = New clsAsyncUnbuffWriter(_path, True, _
  1560. 1024 * (clsAsyncUnbuffWriter.GetPageSize()), IncomingFileSize)
  1561. Catch ex As Exception
  1562. _path = ex.Message
  1563. ReceivingFile = False
  1564. End Try
  1565. If Not ReceivingFile Then
  1566. Try
  1567. fileWriter.Close()
  1568. Catch ex As Exception
  1569. End Try
  1570. Return False
  1571. End If
  1572. End Function
  1573. Private Function HandleIncomingFileBytes(ByRef bytes() As Byte) As Boolean
  1574. Try
  1575. fileWriter.Write(bytes, bytes.Length)
  1576. HandleIncomingFileBytes = True
  1577. Catch ex As Exception
  1578. HandleIncomingFileBytes = False
  1579. End Try
  1580. End Function
  1581. Private Sub FinishReceivingTheFile()
  1582. Try
  1583. fileWriter.Close()
  1584. fileWriter = Nothing
  1585. ReceivingFile = False
  1586. Catch ex As Exception
  1587. ReceivingFile = False
  1588. End Try
  1589. End Sub
  1590. Private Sub StopSendingTheFile()
  1591. Try
  1592. SendingFile = False
  1593. fileReader.Close()
  1594. fileReader = Nothing
  1595. GC.GetTotalMemory(True)
  1596. Catch ex As Exception
  1597. SendingFile = False
  1598. GC.GetTotalMemory(True)
  1599. End Try
  1600. End Sub
  1601. Private Sub WrapUpIncomingFile()
  1602. If ReceivingFile Then
  1603. Try
  1604. fileWriter.Close()
  1605. fileWriter = Nothing
  1606. GC.GetTotalMemory(True)
  1607. Catch ex As Exception
  1608. End Try
  1609. Try
  1610. File.Delete(ReceivedFilesFolder & "\" & IncomingFileName)
  1611. Catch ex As Exception
  1612. End Try
  1613. End If
  1614. End Sub
  1615. Private Function CheckSessionPermissions(ByVal cmd As String) As Boolean
  1616. ' Your security code here...
  1617. Return True
  1618. End Function
  1619. Private Function BeginFileSend(ByVal _path As String, ByVal fileLength As Long) As Boolean
  1620. filebytesSent = 0
  1621. Try
  1622. fileReader = New FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.None, clsAsyncUnbuffWriter.GetPageSize)
  1623. SendingFile = True
  1624. BeginFileSend = True
  1625. Catch ex As Exception
  1626. BeginFileSend = False
  1627. _path = ex.Message
  1628. SendingFile = False
  1629. End Try
  1630. Try
  1631. If Not BeginFileSend Then fileReader.Close()
  1632. Catch ex As Exception
  1633. End Try
  1634. End Function
  1635. Private Sub GetMoreFileBytesIfAvailable()
  1636. Dim bytesRead As Integer
  1637. If SendingFile And Not SystemBytesToBeSentAvailable Then
  1638. Try
  1639. If SystemBytesToBeSent.Length <> blockSize Then ReDim SystemBytesToBeSent(blockSize - 1)
  1640. bytesRead = fileReader.Read(SystemBytesToBeSent, 0, blockSize)
  1641. If bytesRead <> blockSize Then ReDim Preserve SystemBytesToBeSent(bytesRead - 1)
  1642. If bytesRead > 0 Then
  1643. SystemOutputChannel = 252 ' File transfer from client to server
  1644. SystemBytesToBeSentAvailable = True
  1645. filebytesSent += bytesRead
  1646. Else
  1647. ReDim SystemBytesToBeSent(blockSize - 1)
  1648. SendExternalSystemMessage("<-Done") ' Send the server a completion notice.
  1649. SystemMessage("<-Done")
  1650. SendingFile = False
  1651. ' Clean up
  1652. fileReader.Close()
  1653. fileReader = Nothing
  1654. GC.GetTotalMemory(True)
  1655. End If
  1656. Catch ex As Exception
  1657. SendExternalSystemMessage("ERR: " & ex.Message)
  1658. ' We're finished.
  1659. ReDim SystemBytesToBeSent(blockSize - 1)
  1660. SendingFile = False
  1661. fileReader.Close()
  1662. End Try
  1663. End If
  1664. End Sub
  1665. Private Function GetFilenameFromPath(ByVal filePath As String) As String
  1666. Dim filePathParts() As String
  1667. If filePath.Trim = "" Then Return ""
  1668. filePathParts = Split(filePath, "\")
  1669. GetFilenameFromPath = filePathParts(filePathParts.Length - 1)
  1670. End Function
  1671. Private Sub HandleIncomingSystemMessages(ByVal bytes() As Byte, ByVal channel As Byte)
  1672. If channel = 254 Then ' Text commands / messages passed between server and client
  1673. Dim message As String = BytesToString(bytes)
  1674. Dim tmp As String = ""
  1675. Dim filePath As String
  1676. ' Get File Request: The server wants us to send them a file.
  1677. If message.Length > 4 Then tmp = message.Substring(0, 4)
  1678. If tmp = "GFR:" Then ' Get File Request
  1679. ' Get file path...
  1680. filePath = message.Substring(4, message.Length - 4)
  1681. ' Does it exist?
  1682. If File.Exists(message.Substring(4, message.Length - 4)) Then
  1683. ' Are we already busy sending them a file?
  1684. If Not SendingFile Then
  1685. Dim _theFilesInfo As New FileInfo(filePath)
  1686. outgoingFileName = GetFilenameFromPath(filePath)
  1687. outgoingFileSize = CULng(_theFilesInfo.Length)
  1688. If BeginFileSend(filePath, _theFilesInfo.Length) Then
  1689. ' Send only the file NAME. It will have a different path on the other side.
  1690. SendExternalSystemMessage("Sending:" & outgoingFileName & _
  1691. ":" & outgoingFileSize.ToString)
  1692. SystemMessage("Sending file:" & outgoingFileName)
  1693. Else
  1694. ' FilePath contains the error message.
  1695. SendExternalSystemMessage("ERR: " & filePath)
  1696. End If
  1697. Else
  1698. ' There's already a GFR in progress.
  1699. SendExternalSystemMessage("ERR: File: ''" & _
  1700. FileBeingSentPath & _
  1701. "'' is still in progress. Only one file " & _
  1702. "may be transfered (from client to server) at a time.")
  1703. End If
  1704. Else
  1705. ' File doesn't exist. Send an error.
  1706. SendExternalSystemMessage("ERR: The requested file can not be found by the server.")
  1707. End If
  1708. End If
  1709. If message.Length > 7 Then tmp = message.Substring(0, 8)
  1710. If tmp = "Sending:" Then
  1711. ' Strip away the headder...
  1712. Dim msgParts() As String = Split(message, ":")
  1713. IncomingFileSize = Convert.ToInt64(msgParts(2))
  1714. IncomingFileName = msgParts(1)
  1715. tmp = ReceivedFilesFolder & "\" & IncomingFileName
  1716. SystemMessage("Receiving file: " & IncomingFileName)
  1717. If Not BeginToReceiveAFile(tmp) Then
  1718. SystemMessage("ERR: " & tmp)
  1719. SendExternalSystemMessage("Abort<-")
  1720. End If
  1721. End If
  1722. If message.Length > 10 Then tmp = message.Substring(0, 10)
  1723. If tmp = "blocksize:" Then
  1724. Dim msgParts() As String = Split(message, ":")
  1725. blockSize = Convert.ToUInt16(msgParts(1))
  1726. End If
  1727. If message = "->Done" Then
  1728. FinishReceivingTheFile()
  1729. SystemMessage("->Done")
  1730. End If
  1731. ' We've been notified that no file data will be forthcoming.
  1732. If message = "Abort->" Then
  1733. FinishReceivingTheFile()
  1734. SystemMessage("->Aborted.")
  1735. Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Normal
  1736. Try
  1737. File.Delete(ReceivedFilesFolder & "\" & IncomingFileName)
  1738. Catch ex As Exception
  1739. End Try
  1740. End If
  1741. ' Send File Request: The server wants to send us a file.
  1742. If message.Length > 4 Then tmp = message.Substring(0, 4)
  1743. If tmp = "SFR:" Then
  1744. If CheckSessionPermissions("SFR") Then
  1745. Dim parts() As String
  1746. parts = Split(message, "SFR:")
  1747. SendExternalSystemMessage("GFR:" & parts(1))
  1748. Else
  1749. ' This user doesn't have rights to this file. Send an error.
  1750. SendExternalSystemMessage("ERR: You do not have permission to send files. Access Denied.")
  1751. End If
  1752. End If
  1753. ' Notification that the server has complied with our
  1754. ' request to stop sending bytes for this
  1755. ' (server->client) file transfer.
  1756. If message = "->Aborted." Then
  1757. SystemMessage("->Aborted.")
  1758. WrapUpIncomingFile()
  1759. End If
  1760. ' Notification that the server has complied with our
  1761. ' request to stop recieving bytes for this
  1762. ' (client->server) file transfer.
  1763. If message = "<-Aborted." Then
  1764. SystemMessage("<-Aborted.")
  1765. End If
  1766. If message.Length > 4 Then tmp = message.Substring(0, 4)
  1767. If tmp = "ERR:" Then ' The server has sent us an error message.
  1768. ' Pass it on up to the user.
  1769. SystemMessage(message)
  1770. End If
  1771. ' New queue throttling code
  1772. If message = "pause" Then
  1773. 'sendBuffer.PauseSending()
  1774. End If
  1775. If message = "resume" Then
  1776. 'sendBuffer.ResumeSending()
  1777. End If
  1778. ' Preform gracefull shutdown.
  1779. If message = "close" then
  1780. Throw New Exception("Server initiated gracefull shutdown.")
  1781. End If
  1782. ElseIf channel = 253 Then ' File transfer from server to client
  1783. Try
  1784. If ReceivingFile Then
  1785. HandleIncomingFileBytes(bytes)
  1786. fileBytesRecieved += bytes.LongLength
  1787. End If
  1788. Catch ex As Exception
  1789. End Try
  1790. ElseIf channel = 252 Then ' File transfer from client to server
  1791. ElseIf channel = 251 Then ' reserved.
  1792. End If
  1793. End Sub
  1794. Private Function HandleOutgoingInternalSystemMessage() As Boolean
  1795. Dim tmp(1) As Byte
  1796. HandleOutgoingInternalSystemMessage = False
  1797. Dim _size As Integer
  1798. GetMoreFileBytesIfAvailable()
  1799. ' Handle outgoing system stuff here
  1800. If SystemBytesToBeSentAvailable = True Then
  1801. HandleOutgoingInternalSystemMessage = True
  1802. If SystemBytesToBeSent.Length > blockSize Then
  1803. ' Send Channel
  1804. tmp(0) = SystemOutputChannel
  1805. Stream.Write(tmp, 0, 1)
  1806. bytesSentThisSecond += 1
  1807. ' Send packet size
  1808. _size = blockSize
  1809. tmp = BitConverter.GetBytes(_size)
  1810. Stream.Write(tmp, 0, 2)
  1811. bytesSentThisSecond += 2
  1812. ' Send packet
  1813. Stream.Write(GetSome(SystemBytesToBeSent, blockSize, SystemBytesToBeSentAvailable), 0, _size)
  1814. bytesSentThisSecond += _size
  1815. Else
  1816. ' Send Channel
  1817. tmp(0) = SystemOutputChannel
  1818. Stream.Write(tmp, 0, 1)
  1819. bytesSentThisSecond += 1
  1820. ' Send packet size
  1821. _size = SystemBytesToBeSent.Length
  1822. tmp = BitConverter.GetBytes(_size)
  1823. Stream.Write(tmp, 0, 2)
  1824. bytesSentThisSecond += 2
  1825. ' Send packet
  1826. Stream.Write(SystemBytesToBeSent, 0, _size)
  1827. bytesSentThisSecond += _size
  1828. SystemBytesToBeSentAvailable = False
  1829. End If
  1830. End If
  1831. End Function
  1832. Private Function HandleOutgoingUserData() As Boolean
  1833. Dim tmp(1) As Byte
  1834. Dim _size As UShort
  1835. Dim notify As Boolean = False
  1836. Static packet(0) As Byte
  1837. Dim msg As message = Nothing
  1838. Dim stopMessageSent As Boolean = False
  1839. If Not UserBytesToBeSentAvailable then
  1840. If sendQueue.TryDequeue(msg) then
  1841. UserBytesToBeSentAvailable = True
  1842. UserBytesToBeSent = New MemoryStream(msg.bytes)
  1843. UserOutputChannel = msg.dataChannel
  1844. End If
  1845. End If
  1846. If theClientIsStopping() then
  1847. UserBytesToBeSentAvailable = True
  1848. UserBytesToBeSent = New MemoryStream(StrToByteArray("close"))
  1849. UserOutputChannel = 254
  1850. stopMessageSent = True
  1851. End If
  1852. If UserBytesToBeSentAvailable = True Then
  1853. Try
  1854. If (UserBytesToBeSent.Length - UserBytesToBeSent.Position) > blockSize Then
  1855. ' Send Channel
  1856. tmp(0) = UserOutputChannel
  1857. Stream.Write(tmp, 0, 1)
  1858. ' Send packet size
  1859. _size = blockSize
  1860. tmp = BitConverter.GetBytes(_size)
  1861. Stream.Write(tmp, 0, 2)
  1862. ' Send packet
  1863. If packet.Length <> _size Then ReDim packet(_size - 1)
  1864. UserBytesToBeSent.Read(packet, 0, _size)
  1865. 'Client.NoDelay = True
  1866. Stream.Write(packet, 0, _size)
  1867. bytesSentThisSecond += 3 + _size
  1868. ' Check to see if we've sent it all...
  1869. If UserBytesToBeSent.Length = UserBytesToBeSent.Position Then
  1870. UserBytesToBeSentAvailable = False
  1871. notify = True
  1872. End If
  1873. Else
  1874. ' Send Channel
  1875. tmp(0) = UserOutputChannel
  1876. Stream.Write(tmp, 0, 1)
  1877. ' Send packet size
  1878. _size = Convert.ToUInt16(UserBytesToBeSent.Length - UserBytesToBeSent.Position)
  1879. tmp = BitConverter.GetBytes(_size)
  1880. Stream.Write(tmp, 0, 2)
  1881. ' Send packet
  1882. If packet.Length <> _size Then ReDim packet(_size - 1)
  1883. UserBytesToBeSent.Read(packet, 0, _size)
  1884. 'Client.NoDelay = True
  1885. Stream.Write(packet, 0, _size)
  1886. bytesSentThisSecond += 3 + _size
  1887. UserBytesToBeSentAvailable = False
  1888. notify = True
  1889. End If
  1890. Catch ex As Exception
  1891. ' Report error attempting to send user data.
  1892. Debug.WriteLine("Unexpected error in TcpCommClient\HandleOutgoingUserData: " & ex.Message)
  1893. End Try
  1894. ' Notify the user that the packet has been sent.
  1895. If notify Then SystemMessage("UBS:" & UserOutputChannel)
  1896. If stopMessageSent then Throw New Exception("Client closing gracefully.")
  1897. Return True
  1898. Else
  1899. Return False
  1900. End If
  1901. End Function
  1902. Private Function GetSome(ByRef bytes() As Byte, ByVal chunkToBreakOff As Integer, _
  1903. ByRef bytesToBeSentAvailable As Boolean, _
  1904. Optional ByVal theseAreUserBytes As Boolean = False) As Byte()
  1905. Dim tmp(chunkToBreakOff - 1) As Byte
  1906. Array.Copy(bytes, 0, tmp, 0, chunkToBreakOff)
  1907. GetSome = tmp
  1908. If bytes.Length = chunkToBreakOff Then
  1909. bytesToBeSentAvailable = False
  1910. If theseAreUserBytes Then SystemMessage("UBS")
  1911. Else
  1912. Dim tmp2(bytes.Length - chunkToBreakOff - 1) As Byte
  1913. Array.Copy(bytes, chunkToBreakOff, tmp2, 0, bytes.Length - chunkToBreakOff)
  1914. bytes = tmp2
  1915. End If
  1916. End Function
  1917. Private Sub SystemMessage(ByVal MsgText As String)
  1918. RcvBytes(StrToByteArray(MsgText), 255)
  1919. End Sub
  1920. ' Check to see if our app is closing (set in FormClosing event)
  1921. Private Function theClientIsStopping() As Boolean
  1922. If continue_running = False Then
  1923. theClientIsStopping = True
  1924. Else
  1925. theClientIsStopping = False
  1926. End If
  1927. End Function
  1928. Private Function CalculateMbps(Optional ByVal GetMbps As Boolean = False) As Decimal
  1929. Static averagesCounter As Integer = 0
  1930. Static tmr As Date = Now
  1931. Static lastread As Int32 = 0
  1932. Dim looper As Short = 0
  1933. Dim tmp As Int32 = 0
  1934. If mbpsOneSecondAverage Is Nothing Then ReDim mbpsOneSecondAverage(9)
  1935. If Now >= tmr.AddMilliseconds(250) Then
  1936. averagesCounter += 1
  1937. If averagesCounter < 0 Then averagesCounter = 0
  1938. Select Case averagesCounter
  1939. Case 0
  1940. SyncLock (mbpsSyncObject)
  1941. Try
  1942. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  1943. bytesSentThisSecond = 0
  1944. bytesReceivedThisSecond = 0
  1945. Catch ex As Exception
  1946. averagesCounter = -1
  1947. End Try
  1948. End SyncLock
  1949. Case 1
  1950. SyncLock (mbpsSyncObject)
  1951. Try
  1952. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  1953. bytesSentThisSecond = 0
  1954. bytesReceivedThisSecond = 0
  1955. Catch ex As Exception
  1956. averagesCounter = -1
  1957. End Try
  1958. End SyncLock
  1959. Case 2
  1960. SyncLock (mbpsSyncObject)
  1961. Try
  1962. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  1963. bytesSentThisSecond = 0
  1964. bytesReceivedThisSecond = 0
  1965. Catch ex As Exception
  1966. averagesCounter = -1
  1967. End Try
  1968. End SyncLock
  1969. Case 3
  1970. SyncLock (mbpsSyncObject)
  1971. Try
  1972. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  1973. bytesSentThisSecond = 0
  1974. bytesReceivedThisSecond = 0
  1975. Catch ex As Exception
  1976. averagesCounter = -1
  1977. End Try
  1978. End SyncLock
  1979. End Select
  1980. If averagesCounter > 2 Then averagesCounter = -1
  1981. tmr = Now
  1982. End If
  1983. ' Did they ask us for the Mbps?
  1984. If GetMbps Then
  1985. For looper = 0 To 3
  1986. SyncLock (mbpsSyncObject)
  1987. tmp += mbpsOneSecondAverage(looper)
  1988. End SyncLock
  1989. Next
  1990. CalculateMbps = tmp
  1991. Else
  1992. CalculateMbps = 0
  1993. End If
  1994. End Function
  1995. Private Sub Run()
  1996. Dim puck(1) As Byte : puck(0) = 0
  1997. Dim theBuffer(blockSize - 1) As Byte
  1998. Dim tmp(1) As Byte
  1999. Dim dataChannel As Byte = 0
  2000. Dim packetSize As UShort = 0
  2001. Dim bytesread As Integer
  2002. Dim userOrSystemSwitcher As Integer = 0
  2003. Dim PercentUsage As Short = -1
  2004. Dim connectionLossTimer As Date
  2005. Dim CPUutil As New CpuMonitor
  2006. CPUutil.Start()
  2007. Try
  2008. Client = New TcpClient
  2009. Client.Connect(IP, Port)
  2010. ' Connection Accepted.
  2011. Stream = Client.GetStream()
  2012. ' Set the send and receive buffers to the maximum
  2013. ' size allowable in this application...
  2014. Client.Client.ReceiveBufferSize = 65535
  2015. Client.Client.SendBufferSize = 65535
  2016. ' no delay on partially filled packets...
  2017. ' Send it all as fast as possible.
  2018. Client.NoDelay = True
  2019. ' Pass a message up to the user about our status.
  2020. isRunning = True
  2021. SystemMessage("Connected.")
  2022. ' Start the communication loop
  2023. Do
  2024. ' Check to see if our app is shutting down.
  2025. 'If theClientIsStopping() Then Exit Do
  2026. ' Normal communications...
  2027. If weHaveThePuck Then
  2028. ' Send user data if there is any to be sent.
  2029. userOrSystemSwitcher += 1
  2030. Select Case userOrSystemSwitcher
  2031. Case 1
  2032. HandleOutgoingUserData()
  2033. Case 2
  2034. HandleOutgoingInternalSystemMessage()
  2035. End Select
  2036. If userOrSystemSwitcher > 1 Then userOrSystemSwitcher = 0
  2037. ' After sending our data, send the puck
  2038. Stream.Write(puck, 0, 1)
  2039. ' Uncomment this to see control bit traffic as part of your Mbps
  2040. 'bytesSentThisSecond += 1
  2041. weHaveThePuck = False
  2042. End If
  2043. If theBuffer.Length < 2 Then ReDim theBuffer(1)
  2044. ' Read in the control byte.
  2045. Stream.Read(theBuffer, 0, 1)
  2046. dataChannel = theBuffer(0)
  2047. ' Uncomment this to see control bit traffic as part of your Mbps
  2048. 'bytesReceivedThisSecond += 1
  2049. ' If it's just the puck (communictaion syncronization byte),
  2050. ' set weHaveThePuck true and that's all. dataChannel 0 is
  2051. ' reserved for the puck.
  2052. If dataChannel = 0 Then
  2053. weHaveThePuck = True
  2054. Else
  2055. ' It's not the puck: It's an incoming packet.
  2056. ' Get the packet size:
  2057. tmp(0) = Convert.ToByte(Stream.ReadByte)
  2058. tmp(1) = Convert.ToByte(Stream.ReadByte)
  2059. packetSize = BitConverter.ToUInt16(tmp, 0)
  2060. If theBuffer.Length <> packetSize Then ReDim theBuffer(packetSize - 1)
  2061. bytesReceivedThisSecond += 2
  2062. ' Get the packet:
  2063. connectionLossTimer = Now
  2064. Do
  2065. ' Read bytes in...
  2066. bytesread += Stream.Read(theBuffer, bytesread, (packetSize - bytesread))
  2067. ' If it takes longer then 3 seconds to get a packet, we've lost connection.
  2068. If connectionLossTimer.AddSeconds(3) < Now Then Exit Try
  2069. Loop While bytesread < packetSize
  2070. bytesread = 0
  2071. ' Record bytes read for throttling...
  2072. bytesReceivedThisSecond += packetSize
  2073. ' Handle the packet...
  2074. If dataChannel > 250 Then
  2075. ' this is an internal system packet
  2076. HandleIncomingSystemMessages(theBuffer, dataChannel)
  2077. Else
  2078. ' Hand data off to the calling thread.
  2079. RcvBytes(theBuffer, dataChannel)
  2080. End If
  2081. End If
  2082. CalculateMbps(False)
  2083. ' Measure and display the CPU usage of the client (this thread).
  2084. If PercentUsage <> CPUutil.ThreadUsage Then
  2085. PercentUsage = CPUutil.ThreadUsage
  2086. SystemMessage("" & PercentUsage & "% Thread Usage (" & CPUutil.CPUusage & "% across all CPUs)")
  2087. End If
  2088. Loop
  2089. Catch ex As Exception
  2090. ' An unexpected error.
  2091. errMsg = "Error in run thread: " & ex.Message
  2092. End Try
  2093. Try
  2094. fileWriter.Close()
  2095. Catch ex As Exception
  2096. End Try
  2097. Try
  2098. CPUutil.StopWatcher()
  2099. Client.Client.Close()
  2100. SystemMessage("Disconnected.")
  2101. Catch ex As Exception
  2102. ' An unexpected error.
  2103. Debug.WriteLine("Unexpected error in Client\theClientIsStopping: " & ex.Message)
  2104. End Try
  2105. WrapUpIncomingFile()
  2106. isRunning = False
  2107. messageIn.Close()
  2108. End Sub
  2109. End Class
  2110. Private Class CpuMonitor
  2111. Private Class Win32
  2112. <DllImport("kernel32.dll")> _
  2113. Public Shared Function GetCurrentThreadId() As Integer
  2114. End Function
  2115. End Class
  2116. Private NativeThreadID As Integer
  2117. Private WatcherRunning As Boolean = False
  2118. Private th1 As Thread
  2119. Private _CPUusage As Double
  2120. Private _ThreadUsage As Double
  2121. Public Sub New()
  2122. NativeThreadID = Win32.GetCurrentThreadId
  2123. End Sub
  2124. Public Sub New(ByVal _NativeThreadID As Int16)
  2125. NativeThreadID = _NativeThreadID
  2126. End Sub
  2127. Private Function GetCurrentNativeThreadID() As Integer
  2128. GetCurrentNativeThreadID = Win32.GetCurrentThreadId
  2129. End Function
  2130. ' Set the native ID of a process thread to be watched, or get your native thread id
  2131. Public Property GetNativeThreadID() As Integer
  2132. Get
  2133. Return GetCurrentNativeThreadID()
  2134. End Get
  2135. Set(ByVal value As Integer)
  2136. NativeThreadID = value
  2137. End Set
  2138. End Property
  2139. Public ReadOnly Property IsRunning() As Boolean
  2140. Get
  2141. Return WatcherRunning
  2142. End Get
  2143. End Property
  2144. Public ReadOnly Property ThreadUsage() As Short
  2145. Get
  2146. Return CShort(_ThreadUsage)
  2147. End Get
  2148. End Property
  2149. Public ReadOnly Property CPUusage() As Short
  2150. Get
  2151. Return CShort(_CPUusage)
  2152. End Get
  2153. End Property
  2154. Public Sub StopWatcher()
  2155. WatcherRunning = False
  2156. End Sub
  2157. Public Sub Start()
  2158. th1 = New System.Threading.Thread(AddressOf StartWatcher)
  2159. th1.Start()
  2160. End Sub
  2161. Private Sub StartWatcher()
  2162. 'Dim threadCollection As System.Diagnostics.ProcessThreadCollection
  2163. Dim threadCollection As System.Diagnostics.ProcessThreadCollection
  2164. Dim CPUs, t As Int16
  2165. Dim count, managedThreadID As Integer
  2166. Dim CPUtimeEnd, CPUtimeStart, CurrentTimeSpent, onePercent, average(4), tmp As Double
  2167. CPUs = Convert.ToInt16(Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"))
  2168. threadCollection = System.Diagnostics.Process.GetCurrentProcess().Threads
  2169. managedThreadID = 0
  2170. For count = 0 To threadCollection.Count - 1
  2171. If threadCollection.Item(count).Id = NativeThreadID Then
  2172. managedThreadID = count
  2173. End If
  2174. Next
  2175. If managedThreadID = 0 Then
  2176. ' An unexpected error.
  2177. Debug.WriteLine("Unexpected error in ThreadCPUusageWatcher\StartWatcher: Thread could not be found.")
  2178. Exit Sub
  2179. End If
  2180. WatcherRunning = True
  2181. count = 0
  2182. Try
  2183. onePercent = 2
  2184. Do While WatcherRunning = True
  2185. ' Check the cpu usage every 200 msecs...
  2186. CPUtimeStart = threadCollection.Item(managedThreadID).TotalProcessorTime.TotalMilliseconds
  2187. Thread.Sleep(200)
  2188. CPUtimeEnd = threadCollection.Item(managedThreadID).TotalProcessorTime.TotalMilliseconds
  2189. ' Average the thread's CPU usage out over 1 second...
  2190. CurrentTimeSpent = CPUtimeEnd - CPUtimeStart
  2191. average(count) = CurrentTimeSpent / onePercent
  2192. count += 1
  2193. tmp = 0
  2194. For t = 0 To 4
  2195. tmp += average(t)
  2196. Next
  2197. tmp = tmp / 5
  2198. _ThreadUsage = tmp
  2199. If _ThreadUsage > 100 Then _ThreadUsage = 100
  2200. _CPUusage = _ThreadUsage / CPUs
  2201. If count = 5 Then
  2202. count = 0
  2203. End If
  2204. Loop
  2205. Catch ex As Exception
  2206. ' An unexpected error.
  2207. Debug.WriteLine("Unexpected error in ThreadCPUusageWatcher\StartWatcher: " & ex.Message)
  2208. End Try
  2209. End Sub
  2210. End Class
  2211. Public Class ServerRequest
  2212. Private serverIp As String
  2213. Private port As Integer
  2214. Private un As String
  2215. Private pw As String
  2216. Private serverReply As String
  2217. Private replyComplete As Boolean
  2218. Private request As String
  2219. Private thisReplyList As List(Of String)
  2220. Public Sub new(ByVal _serverIpAddress As String, ByVal _serverPort As Integer)
  2221. serverIp = _serverIpAddress
  2222. port = _serverPort
  2223. serverReply = ""
  2224. replyComplete = False
  2225. End Sub
  2226. Public Sub ImportReplyString(ByVal replyString As String)
  2227. serverReply = replyString
  2228. End Sub
  2229. Public Sub AddRequestItem(ByVal key As String, ByVal value As String, Optional ByVal separator As String = vbCrLf)
  2230. If request = "" then request = separator
  2231. If key <> "" and value <> "" then
  2232. request += key & "=" & value & separator
  2233. End If
  2234. End Sub
  2235. Public Function Send(Optional ByVal timeoutSeconds As Integer = 5, Optional ByRef errMsg As String = "") As Boolean
  2236. If request.Length > 0 then
  2237. If thisReplyList IsNot Nothing Then thisReplyList.Clear()
  2238. serverReply = ""
  2239. Dim reply As String = SendRequest(request, timeoutSeconds, errMsg)
  2240. If reply <> "N/C" and reply <> "N/R" then
  2241. Return True
  2242. Else
  2243. If errMsg = "" then errMsg = "Reply from " & serverIp.ToString &" was: " & reply
  2244. End If
  2245. Else
  2246. errMsg = "Request string can not be empty"
  2247. End If
  2248. Return False
  2249. End Function
  2250. Public Function GetReplyStringItems(Optional ByVal separator As String = vbCrLf) As List(Of String)
  2251. If thisReplyList is Nothing then thisReplyList = New List(Of String)
  2252. If thisReplyList.Count = 0 then
  2253. Try
  2254. If serverReply.Length > 0 Then
  2255. Dim theseItems() As String = Split(serverReply, separator)
  2256. If theseItems.Length > 0 Then thisReplyList.AddRange(theseItems)
  2257. End If
  2258. Catch ex As Exception
  2259. End Try
  2260. End If
  2261. 'Dim tmp As String = ""
  2262. 'For Each item As String In thisReplyList
  2263. ' tmp += item & " / "
  2264. 'Next
  2265. 'log("Replystrings found:" & tmp, "Bric Video Service", EventLogEntryType.Information)
  2266. Return thisReplyList
  2267. End Function
  2268. Public Function GetReplyStringItem(ByVal key As String, Optional ByVal separator As String = vbCrLf) As String
  2269. Dim keyValueItems As List(Of String) = GetReplyStringItems(separator)
  2270. Dim keyValuePair() As String
  2271. If keyValueItems.Count > 0 then
  2272. For Each item As String In keyValueItems
  2273. Try
  2274. keyValuePair = Split(item, "=")
  2275. If keyValuePair(0) = key then
  2276. 'log("Asked for:" & key & ", returning:" & keyValuePair(1), "Bric Video Service", EventLogEntryType.Information)
  2277. Return keyValuePair(1)
  2278. End If
  2279. Catch ex As Exception
  2280. End Try
  2281. Next
  2282. End If
  2283. 'log("Asked for:" & key & ", returning ''", "Bric Video Service", EventLogEntryType.Information)
  2284. Return ""
  2285. End Function
  2286. Public Function GetReplyStringItemAsShort(ByVal key As String, Optional ByVal separator As String = vbCrLf) As Short
  2287. Dim value As String = GetReplyStringItem(key, separator)
  2288. Try
  2289. If value <> "" Then Return Convert.ToInt16(value)
  2290. Catch ex As Exception
  2291. End Try
  2292. Return Nothing
  2293. End Function
  2294. Public Function GetReplyStringItemAsDate(ByVal key As String, Optional ByVal separator As String = vbCrLf) As Date
  2295. Dim value As String = GetReplyStringItem(key, separator)
  2296. Try
  2297. If value <> "" Then Return Convert.ToDateTime(value)
  2298. Catch ex As Exception
  2299. End Try
  2300. Return Nothing
  2301. End Function
  2302. Public Function GetReplyString() As String
  2303. Return serverReply
  2304. End Function
  2305. ' Send "cmd=stuff here" & vbCrLf & "something else=more stuff" & vbCrLf...
  2306. Public Function SendRequest(ByVal requestString As String, Optional ByVal timeoutSeconds As Integer = 5, _
  2307. Optional ByRef errMsg As String = "") As String
  2308. ' Handle TCP communication here:
  2309. Dim client As New TcpComm.Client(AddressOf ClientCallback)
  2310. ' Attempt to connect to the server. If not - return N/C (No Connection)
  2311. If Not client.Connect(serverIp, port, "", errMsg) Then Return "N/C"
  2312. ' Send our request, and wait for a reply...
  2313. client.SendBytes(StrToByteArray("<text>" & requestString & "</text>"), 10)
  2314. Dim timeOut As Date = Now
  2315. While Not replyComplete
  2316. If Now > timeOut.AddSeconds(timeoutSeconds) Then Exit While ' Bail after timeoutSeconds seconds.
  2317. Threading.Thread.Sleep(5)
  2318. End While
  2319. client.Close()
  2320. If serverReply.Length > 0 then
  2321. ' If we got a good reply...
  2322. If replyComplete then ' Remove the tags.
  2323. serverReply = serverReply.Replace("<text>", "")
  2324. serverReply = serverReply.Replace("</text>", "")
  2325. End If
  2326. Return serverReply
  2327. End If
  2328. Return "N/R"
  2329. End Function
  2330. Private Sub ClientCallback(ByVal bytes() As Byte, ByVal dataChannel As Integer)
  2331. If dataChannel = 10 Then
  2332. ' Our data arrived.
  2333. serverReply += BytesToString(bytes)
  2334. If serverReply.Contains("</text>") then replyComplete = True
  2335. End If
  2336. End Sub
  2337. End Class
  2338. End Class