PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/SteamKit2/SteamKit2/Steam2/ContentServerClient.cs

https://bitbucket.org/VoiDeD/steamre/
C# | 674 lines | 394 code | 120 blank | 160 comment | 39 complexity | a9607628fc8e19bce158d8718f1cddfe MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, BSD-3-Clause
  1. using System;
  2. using System.IO;
  3. using System.IO.Compression;
  4. using System.Security.Cryptography;
  5. namespace SteamKit2
  6. {
  7. /// <summary>
  8. /// Represents an exception that can occur when doing Steam2 actions.
  9. /// </summary>
  10. [Serializable]
  11. public class Steam2Exception : Exception
  12. {
  13. /// <summary>
  14. /// Initializes a new instance of the <see cref="Steam2Exception"/> class.
  15. /// </summary>
  16. public Steam2Exception()
  17. : base()
  18. {
  19. }
  20. /// <summary>
  21. /// Initializes a new instance of the <see cref="Steam2Exception"/> class.
  22. /// </summary>
  23. /// <param name="msg">The message.</param>
  24. public Steam2Exception( string msg )
  25. : base( msg )
  26. {
  27. }
  28. /// <summary>
  29. /// Initializes a new instance of the <see cref="Steam2Exception"/> class.
  30. /// </summary>
  31. /// <param name="msg">The message.</param>
  32. /// <param name="innerException">The inner exception.</param>
  33. public Steam2Exception( string msg, Exception innerException )
  34. : base( msg, innerException )
  35. {
  36. }
  37. }
  38. /// <summary>
  39. /// Represents a client that is capable of connecting to a Steam2 content server.
  40. /// </summary>
  41. public sealed class ContentServerClient : ServerClient
  42. {
  43. /// <summary>
  44. /// These credentials must be supplied when attempting to open a storage session for a depot which requires it.
  45. /// </summary>
  46. public sealed class Credentials
  47. {
  48. /// <summary>
  49. /// Gets or sets the Steam2 ServerTGT.
  50. /// </summary>
  51. /// <value>The ServerTGT.</value>
  52. public Steam2Ticket Steam2Ticket { get; set; }
  53. /// <summary>
  54. /// Gets or sets the Steam3 session token.
  55. /// </summary>
  56. /// <value>The session token.</value>
  57. public ulong SessionToken { get; set; }
  58. /// <summary>
  59. /// Gets or sets the Steam3 app ticket for the app being requested.
  60. /// </summary>
  61. /// <value>The app ticket.</value>
  62. public byte[] AppTicket { get; set; }
  63. }
  64. /// <summary>
  65. /// Opens a storage session with the storage server.
  66. /// </summary>
  67. /// <param name="depotId">The depot id.</param>
  68. /// <param name="depotVersion">The depot version.</param>
  69. /// <param name="cellId">The cell id.</param>
  70. /// <param name="credentials">The credentials.</param>
  71. /// <param name="doHandshake">Whether or not to send the handshake and reopen cell</param>
  72. /// <returns>A new StorageSession object for the session.</returns>
  73. public StorageSession OpenStorage( uint depotId, uint depotVersion, uint cellId, Credentials credentials, bool doHandshake = true )
  74. {
  75. if (doHandshake)
  76. {
  77. bool bRet = this.HandshakeServer((ESteam2ServerType)7);
  78. if (!bRet)
  79. throw new Steam2Exception("Storage handshake with content server failed");
  80. bRet = this.SendCommand(
  81. 0, // open storage
  82. cellId
  83. );
  84. byte success = this.Socket.Reader.ReadByte();
  85. if (success == 0)
  86. throw new Steam2Exception(string.Format("Unable to open storage depot for cellid {0}", cellId));
  87. ushort bannerLen = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt16());
  88. byte[] bannerData = this.Socket.Reader.ReadBytes(bannerLen);
  89. }
  90. return new StorageSession( this, depotId, depotVersion, credentials );
  91. }
  92. /// <summary>
  93. /// Opens a storage session with the storage server.
  94. /// </summary>
  95. /// <param name="depotId">The depot id.</param>
  96. /// <param name="depotVersion">The depot version.</param>
  97. /// <param name="cellId">The cell id.</param>
  98. /// <param name="doHandshake">Whether or not to send the handshake and reopen cell</param>
  99. /// <returns>A new StorageSession object for the session.</returns>
  100. public StorageSession OpenStorage( uint depotId, uint depotVersion, uint cellId, bool doHandshake = true )
  101. {
  102. return OpenStorage( depotId, depotVersion, cellId, null, doHandshake );
  103. }
  104. /// <summary>
  105. /// Opens a storage session with the storage server.
  106. /// </summary>
  107. /// <param name="depotId">The depot id.</param>
  108. /// <param name="depotVersion">The depot version.</param>
  109. /// <param name="doHandshake">Whether or not to send the handshake and reopen cell</param>
  110. /// <returns>A new StorageSession object for the session.</returns>
  111. public StorageSession OpenStorage( uint depotId, uint depotVersion, bool doHandshake = true )
  112. {
  113. return OpenStorage( depotId, depotVersion, 0, doHandshake );
  114. }
  115. /// <summary>
  116. /// Opens a package session with the package server.
  117. /// </summary>
  118. /// <param name="cellId">The cell id.</param>
  119. /// <returns>A new PackageSession object for the session.</returns>
  120. public PackageSession OpenPackage( uint cellId )
  121. {
  122. bool bRet = this.HandshakeServer( ( ESteam2ServerType )3 );
  123. if ( !bRet )
  124. throw new Steam2Exception( "Package handshake with content server failed" );
  125. return new PackageSession( this, cellId );
  126. }
  127. /// <summary>
  128. /// Requests the cell ID of the currently connected content server.
  129. /// </summary>
  130. /// <returns>The cell ID of the server.</returns>
  131. public uint GetCellID()
  132. {
  133. if ( !this.HandshakeServer( ( ESteam2ServerType )3 ) )
  134. throw new Steam2Exception( "Package handshake with content server failed" );
  135. TcpPacket packet = new TcpPacket();
  136. packet.Write( ( uint )2 );
  137. try
  138. {
  139. this.Socket.Send( packet );
  140. uint cellId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  141. return cellId;
  142. }
  143. catch ( Exception ex )
  144. {
  145. throw new Steam2Exception( "Unable to request cell id", ex );
  146. }
  147. }
  148. /// <summary>
  149. /// This represents a storage session with a storage server, used to download game content.
  150. /// </summary>
  151. public sealed class StorageSession : IDisposable
  152. {
  153. /// <summary>
  154. /// The priority setting for a file download.
  155. /// </summary>
  156. public enum DownloadPriority : byte
  157. {
  158. /// <summary>
  159. /// Low priority.
  160. /// </summary>
  161. Low = 0,
  162. /// <summary>
  163. /// Medium priority.
  164. /// </summary>
  165. Medium = 1,
  166. /// <summary>
  167. /// High priority.
  168. /// </summary>
  169. High = 2,
  170. }
  171. /// <summary>
  172. /// Represents the state of a file within a depot.
  173. /// </summary>
  174. public enum FileMode
  175. {
  176. /// <summary>
  177. /// No special handling is required.
  178. /// </summary>
  179. None = 0,
  180. /// <summary>
  181. /// This file is compressed.
  182. /// </summary>
  183. Compressed = 1,
  184. /// <summary>
  185. /// This file is compressed and encrypted.
  186. /// </summary>
  187. EncryptedAndCompressed = 2,
  188. /// <summary>
  189. /// This file is encrypted.
  190. /// </summary>
  191. Encrypted = 3,
  192. }
  193. /// <summary>
  194. /// Gets the depot ID this session instance is for.
  195. /// </summary>
  196. public uint DepotID { get; private set; }
  197. /// <summary>
  198. /// Gets the depot version this session instance is for.
  199. /// </summary>
  200. public uint DepotVersion { get; private set; }
  201. uint ConnectionID;
  202. uint MessageID;
  203. uint StorageID;
  204. ContentServerClient client;
  205. TcpSocket Socket { get { return client.Socket; } }
  206. static readonly byte[] aesIV = new byte[ 16 ];
  207. internal StorageSession( ContentServerClient cli, uint depotId, uint depotVersion, Credentials credentials )
  208. {
  209. this.DepotID = depotId;
  210. this.DepotVersion = depotVersion;
  211. this.client = cli;
  212. bool bRet = false;
  213. if ( credentials == null || credentials.Steam2Ticket == null )
  214. {
  215. bRet = this.SendCommand(
  216. 9, // open storage
  217. ConnectionID,
  218. MessageID,
  219. depotId,
  220. depotVersion
  221. );
  222. }
  223. else
  224. {
  225. byte[] serverTgt = credentials.Steam2Ticket.Entries[ 14 ].Data; // god help this never change
  226. bRet = this.SendCommand(
  227. 10, // open storage with login
  228. ConnectionID,
  229. MessageID,
  230. depotId,
  231. depotVersion,
  232. ( ushort )serverTgt.Length,
  233. serverTgt,
  234. NetHelpers.EndianSwap( credentials.SessionToken ),
  235. ( byte )credentials.AppTicket.Length,
  236. credentials.AppTicket
  237. );
  238. }
  239. // the server sends us back the connection and message ids
  240. // the client probably performs a sanity check?
  241. uint connId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  242. uint msgId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  243. byte hasDepot = this.Socket.Reader.ReadByte();
  244. // the server gives us 0x1 if the depot doesn't exist or requires authentication
  245. if ( hasDepot != 0 )
  246. throw new Steam2Exception( "Content server does not have depot, or valid credentials were not given" );
  247. StorageID = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  248. uint storageChecksum = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  249. this.ConnectionID++;
  250. }
  251. /// <summary>
  252. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  253. /// </summary>
  254. public void Dispose()
  255. {
  256. this.SendCommand( 3,
  257. this.StorageID,
  258. this.MessageID
  259. );
  260. }
  261. /// <summary>
  262. /// Downloads the <see cref="Steam2Manifest"/> which contains metadata representing the files within the depot.
  263. /// </summary>
  264. /// <returns></returns>
  265. public Steam2Manifest DownloadManifest()
  266. {
  267. bool bRet = this.SendCommand(
  268. 4, // download manifest
  269. this.StorageID,
  270. this.MessageID
  271. );
  272. uint storId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  273. uint msgId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  274. // name is a guess
  275. byte hasManifest = this.Socket.Reader.ReadByte();
  276. uint manifestLength = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  277. byte[] manifest = new byte[ manifestLength ];
  278. uint manifestChunksToRead = manifestLength;
  279. do
  280. {
  281. uint chunkStorID = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  282. uint chunkMsgID = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  283. uint chunkLen = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  284. chunkLen = Math.Min( chunkLen, manifestChunksToRead );
  285. uint toRead = chunkLen;
  286. while ( toRead > 0 )
  287. {
  288. uint socketRead = ( uint )this.Socket.Reader.Read( manifest, ( int )( ( manifestLength - manifestChunksToRead ) + ( chunkLen - toRead ) ), ( int )toRead );
  289. toRead = toRead - socketRead;
  290. }
  291. manifestChunksToRead = manifestChunksToRead - chunkLen;
  292. } while ( manifestChunksToRead > 0 );
  293. this.MessageID++;
  294. return new Steam2Manifest( manifest );
  295. }
  296. /// <summary>
  297. /// Downloads the <see cref="Steam2ChecksumData"/> for this depot.
  298. /// </summary>
  299. /// <returns></returns>
  300. public Steam2ChecksumData DownloadChecksums()
  301. {
  302. bool bRet = this.SendCommand(
  303. 6, // download checksums
  304. this.StorageID,
  305. this.MessageID
  306. );
  307. uint storId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  308. uint msgId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  309. // name is a(n incorrect) guess
  310. byte hasChecksums = this.Socket.Reader.ReadByte();
  311. uint checksumsLength = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  312. byte[] checksumData = new byte[ checksumsLength ];
  313. uint checksumChunksToRead = checksumsLength;
  314. do
  315. {
  316. uint chunkStorID = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  317. uint chunkMsgID = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  318. uint chunkLen = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  319. chunkLen = Math.Min( chunkLen, checksumChunksToRead );
  320. uint toRead = chunkLen;
  321. while ( toRead > 0 )
  322. {
  323. uint socketRead = ( uint )this.Socket.Reader.Read( checksumData, ( int )( ( checksumsLength - checksumChunksToRead ) + ( chunkLen - toRead ) ), ( int )toRead );
  324. toRead = toRead - socketRead;
  325. }
  326. checksumChunksToRead = checksumChunksToRead - chunkLen;
  327. } while ( checksumChunksToRead > 0 );
  328. this.MessageID++;
  329. return new Steam2ChecksumData( checksumData );
  330. }
  331. /// <summary>
  332. /// Downloads a list of updated FileIDs since the given version.
  333. /// </summary>
  334. /// <param name="oldVersion">The old version to compare to.</param>
  335. /// <returns>A list of FileIDs that have been updated.</returns>
  336. public uint[] DownloadUpdates( uint oldVersion )
  337. {
  338. bool bRet = this.SendCommand(
  339. 5, // download updates
  340. this.StorageID,
  341. this.MessageID,
  342. oldVersion
  343. );
  344. uint storId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  345. uint msgId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  346. byte updateState = this.Socket.Reader.ReadByte();
  347. uint numUpdates = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  348. if ( numUpdates == 0 )
  349. return null;
  350. uint storId2 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  351. uint msgId2 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  352. TcpPacket packet = this.Socket.ReceivePacket();
  353. DataStream ds = new DataStream( packet.GetPayload() );
  354. uint[] fileIdList = new uint[ numUpdates ];
  355. for ( int x = 0 ; x < numUpdates ; ++x )
  356. {
  357. fileIdList[ x ] = ds.ReadUInt32();
  358. }
  359. this.MessageID++;
  360. return fileIdList;
  361. }
  362. /// <summary>
  363. /// Downloads a specific file from the Steam servers to the specified Stream.
  364. /// </summary>
  365. /// <param name="file">The file to download, given from the manifest.</param>
  366. /// <param name="downloadStream">The stream to which file data should be written.</param>
  367. /// <param name="priority">The download priority.</param>
  368. /// <param name="cryptKey">The AES encryption key used for any encrypted files.</param>
  369. /// <returns>A byte array representing the file.</returns>
  370. public void DownloadFileToStream(Steam2Manifest.Node file, Stream downloadStream, DownloadPriority priority = DownloadPriority.Low, byte[] cryptKey = null)
  371. {
  372. if ((file.Attributes & Steam2Manifest.Node.Attribs.EncryptedFile) != 0 && cryptKey == null)
  373. {
  374. throw new Steam2Exception(string.Format("AES encryption key required for file: {0}", file.FullName));
  375. }
  376. const uint MaxParts = 16;
  377. uint numFileparts = (uint)Math.Ceiling((float)file.SizeOrCount / (float)file.Parent.BlockSize);
  378. uint numChunks = (uint)Math.Ceiling((float)numFileparts / (float)MaxParts);
  379. for (uint x = 0; x < numChunks; ++x)
  380. {
  381. byte[] filePart = DownloadFileParts(file, x * MaxParts, MaxParts, priority, cryptKey);
  382. downloadStream.Write(filePart, 0, filePart.Length);
  383. }
  384. }
  385. /// <summary>
  386. /// Downloads a specific file from the Steam servers.
  387. /// </summary>
  388. /// <param name="file">The file to download, given from the manifest.</param>
  389. /// <param name="priority">The download priority.</param>
  390. /// <param name="cryptKey">The AES encryption key used for any encrypted files.</param>
  391. /// <returns>A byte array representing the file.</returns>
  392. public byte[] DownloadFile( Steam2Manifest.Node file, DownloadPriority priority = DownloadPriority.Low, byte[] cryptKey = null )
  393. {
  394. using (var ms = new MemoryStream())
  395. {
  396. DownloadFileToStream( file, ms, priority, cryptKey );
  397. return ms.ToArray();
  398. }
  399. }
  400. byte[] DownloadFileParts( Steam2Manifest.Node file, uint filePart, uint numParts, DownloadPriority priority = DownloadPriority.Low, byte[] cryptKey = null )
  401. {
  402. this.SendCommand(
  403. 7, // download file
  404. this.StorageID,
  405. this.MessageID,
  406. file.FileID,
  407. filePart,
  408. numParts,
  409. ( byte )priority
  410. );
  411. uint storId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  412. uint msgId = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  413. byte hasFile = this.Socket.Reader.ReadByte();
  414. uint numChunks = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  415. uint fileModeValue = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  416. FileMode fileMode = ( FileMode )fileModeValue;
  417. MemoryStream ms = new MemoryStream();
  418. for ( int x = 0 ; x < numChunks ; ++x )
  419. {
  420. uint storId2 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  421. uint msgId2 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  422. uint chunkLen = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  423. uint storId3 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  424. uint msgId3 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  425. uint chunkLen2 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  426. if ( chunkLen == 0 )
  427. continue;
  428. byte[] chunk = null;
  429. int len = 0;
  430. if ( fileMode == FileMode.Compressed )
  431. {
  432. chunk = this.Socket.Reader.ReadBytes( ( int )chunkLen );
  433. len = DecompressFileChunk( ref chunk, ( int )file.Parent.BlockSize );
  434. }
  435. else if ( fileMode == FileMode.Encrypted )
  436. {
  437. len = DecryptFileChunk( out chunk, ( int )chunkLen, cryptKey );
  438. }
  439. else if ( fileMode == FileMode.EncryptedAndCompressed )
  440. {
  441. // Account for 2 integers before the encrypted data
  442. chunkLen -= 8;
  443. // Skip first integer (length of the encrypted data)
  444. this.Socket.Reader.ReadInt32();
  445. // Length of decrypted and decompressed data
  446. int plainLen = this.Socket.Reader.ReadInt32();
  447. DecryptFileChunk( out chunk, ( int )chunkLen, cryptKey );
  448. len = DecompressFileChunk( ref chunk, plainLen );
  449. }
  450. else if ( fileMode == FileMode.None )
  451. {
  452. chunk = this.Socket.Reader.ReadBytes( ( int )chunkLen );
  453. len = chunk.Length;
  454. }
  455. ms.Write( chunk, 0, len );
  456. }
  457. byte[] data = ms.ToArray();
  458. this.MessageID++;
  459. return data;
  460. }
  461. bool SendCommand( byte cmd, params object[] args )
  462. {
  463. return this.client.SendCommand( cmd, args );
  464. }
  465. static int DecompressFileChunk( ref byte[] chunk, int blockSize )
  466. {
  467. using ( MemoryStream chunkStream = new MemoryStream( chunk ) )
  468. using ( DeflateStream ds = new DeflateStream( chunkStream, CompressionMode.Decompress ) )
  469. {
  470. // skip zlib header
  471. chunkStream.Seek( 2, SeekOrigin.Begin );
  472. byte[] decomp = new byte[ blockSize ];
  473. int len = ds.Read( decomp, 0, decomp.Length );
  474. chunk = decomp;
  475. return len;
  476. }
  477. }
  478. int DecryptFileChunk( out byte[] chunk, int chunkLen, byte[] cryptKey )
  479. {
  480. // Round up to nearest AES block size (16 bytes)
  481. int decryptLen = ( chunkLen + 15 ) & ~15;
  482. chunk = new byte[ decryptLen ];
  483. int toRead = chunkLen;
  484. while ( toRead > 0 )
  485. {
  486. toRead -= this.Socket.Reader.Read( chunk, chunkLen - toRead, toRead );
  487. }
  488. using ( var chunkStream = new MemoryStream( chunk ) )
  489. using ( var aes = new RijndaelManaged() )
  490. {
  491. aes.Mode = CipherMode.CFB;
  492. aes.BlockSize = aes.KeySize = 128;
  493. aes.Padding = PaddingMode.None;
  494. using ( var aesTransform = aes.CreateDecryptor( cryptKey, aesIV ) )
  495. using ( var ds = new CryptoStream( chunkStream, aesTransform, CryptoStreamMode.Read ) )
  496. {
  497. byte[] decrypt = new byte[ chunkLen ];
  498. int len = ds.Read( decrypt, 0, decrypt.Length );
  499. chunk = decrypt;
  500. return len;
  501. }
  502. }
  503. }
  504. }
  505. /// <summary>
  506. /// This represents a storage session with a package server, used to download client updates.
  507. /// </summary>
  508. public sealed class PackageSession : IDisposable
  509. {
  510. /// <summary>
  511. /// Gets or sets the cell ID.
  512. /// </summary>
  513. /// <value>The cell ID.</value>
  514. public uint CellID { get; private set; }
  515. ContentServerClient client;
  516. TcpSocket Socket { get { return client.Socket; } }
  517. internal PackageSession( ContentServerClient cli, uint cellId )
  518. {
  519. this.client = cli;
  520. this.CellID = cellId;
  521. }
  522. /// <summary>
  523. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  524. /// </summary>
  525. public void Dispose()
  526. {
  527. TcpPacket packet = new TcpPacket();
  528. packet.Write( ( uint )3 );
  529. // exit package mode
  530. this.Socket.Send( packet );
  531. }
  532. /// <summary>
  533. /// Downloads the specified package file.
  534. /// </summary>
  535. /// <param name="fileName">Name of the file.</param>
  536. /// <returns>A byte array representing the file.</returns>
  537. public byte[] DownloadPackage( string fileName )
  538. {
  539. TcpPacket packet = new TcpPacket();
  540. packet.Write( ( uint )0 ); // unknown, always 0?
  541. packet.Write( ( uint )0 ); // unknown, always 0?
  542. packet.Write( ( uint )fileName.Length );
  543. packet.Write( fileName );
  544. packet.Write( this.CellID );
  545. this.Socket.Send( packet );
  546. // length is sent twice, as two uints
  547. uint len1 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  548. uint len2 = NetHelpers.EndianSwap( this.Socket.Reader.ReadUInt32() );
  549. byte[] packageData = this.Socket.Reader.ReadBytes( ( int )len1 );
  550. return packageData;
  551. }
  552. }
  553. }
  554. }