//----------------------------------------------------------------------- // Private methods //----------------------------------------------------------------------- /// <summary>Connects to the Sign-on Verify server</summary> private void ConnectToSignonVerifyServer() { // Establish authentication channel this.socketConnectorSignonVerify = new SocketConnector(this.serverName, this.useSSL ? TcpPortSignonVerifySSL : TcpPortSignonVerify, this.useSSL, this.ignoreSelfSignedCertificates); // Default current seed information this.clientSeed = 0; this.serverSeed = 0; // Exchange random seeds ulong clientSeed = (ulong)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; BigEndianMemoryStream outputStream = new BigEndianMemoryStream(); //// outputStream.WriteInt(52); // length outputStream.WriteShort(0); // Header ID (0) outputStream.WriteShort(ServerIDSignonVerify); // Server ID outputStream.WriteInt(0); // CS instance outputStream.WriteInt(0); // Correlation ID outputStream.WriteShort(0); // Template length outputStream.WriteShort(0x7003); // ReqReP ID outputStream.WriteInt(10); // Client version LL outputStream.WriteShort(0x1101); // Client version CP outputStream.WriteInt(1); // Client version outputStream.WriteInt(8); // Client data stream level LL outputStream.WriteShort(0x1102); // Client datastream level CP outputStream.WriteShort(2); // Client datastream level outputStream.WriteInt(14); // Client seed LL outputStream.WriteShort(0x1103); // Client seed CP outputStream.WriteLong(clientSeed); // Client seed this.socketConnectorSignonVerify.Write(outputStream.ToArray()); // Retrieve server response byte[] response = this.socketConnectorSignonVerify.Read(); BigEndianMemoryStream inputStream = new BigEndianMemoryStream(); inputStream.Write(response, 0, response.Length); /* * The response comes in the following format: * * Offset (byte) Information Length (byte) * ----------------------------------------------------------- * Fixed header * ----------------------------------------------------------- * 0 Response length 4 * 4 (Reserved) 16 * 20 Result code 4 * 24 (Dynamic fields) see below * ----------------------------------------------------------- * Dynamic fields (Offset is dynamic) * ----------------------------------------------------------- * 0 Field length 4 * 4 Field code 2 * 6 Field data (Field length - 6) */ // Read fixed header inputStream.Position = 0; uint responseLength = inputStream.ReadInt(); if (responseLength < 20) { throw new System.InvalidOperationException("Seeds exchange failed. Bad response length."); } inputStream.Position += 16; uint resultCode = inputStream.ReadInt(); if (resultCode != 0) { throw new System.InvalidOperationException("Seeds exchange failed. Bad return code."); } while (inputStream.Position < responseLength) { uint dynamicFieldLength = inputStream.ReadInt(); ushort dynamicFieldCode = inputStream.ReadShort(); byte[] dynamicFieldData = new byte[dynamicFieldLength - 6]; inputStream.Read(dynamicFieldData, 0, (int)dynamicFieldLength - 6); switch (dynamicFieldCode) { case 0x1101: // Server Version this.serverVersion = Converters.BigEndianToUInt32(dynamicFieldData); break; case 0x1102: // Server Level this.serverLevel = Converters.BigEndianToUInt16(dynamicFieldData); break; case 0x1103: // Server Seed this.serverSeed = Converters.BigEndianToUInt64(dynamicFieldData); break; case 0x1119: // Password Level this.passwordLevel = Converters.BigEndianToUInt8(dynamicFieldData); break; case 0x111F: // Job Name this.jobName = Converters.EbcdicToAsciiString(dynamicFieldData, 4); break; default: break; } } Debug.WriteLine("Seeds were exchanged, return code is 0x" + resultCode.ToString("X8")); this.clientSeed = clientSeed; }