/// <summary> /// Receives the message. /// </summary> private static byte[] ReceiveMessage(Socket sock) { var buf = new byte[4]; sock.Receive(buf); using (var stream = new BinaryHeapStream(buf)) { var size = stream.ReadInt(); buf = new byte[size]; sock.Receive(buf); return(buf); } }
/// <summary> /// Receives the message. /// </summary> private static byte[] ReceiveMessage(Stream sock) { var buf = new byte[4]; var read = sock.Read(buf, 0, 4); Assert.AreEqual(4, read); using (var stream = new BinaryHeapStream(buf)) { var size = stream.ReadInt(); buf = new byte[size]; sock.Read(buf, 0, size); return(buf); } }
/// <summary> /// Decodes the response that we got from <see cref="HandleResponse"/>. /// </summary> private static T DecodeResponse <T>(BinaryHeapStream stream, Func <IBinaryStream, T> readFunc, Func <ClientStatusCode, string, T> errorFunc) { var statusCode = (ClientStatusCode)stream.ReadInt(); if (statusCode == ClientStatusCode.Success) { return(readFunc != null?readFunc(stream) : default(T)); } var msg = BinaryUtils.Marshaller.StartUnmarshal(stream).ReadString(); if (errorFunc != null) { return(errorFunc(statusCode, msg)); } throw new IgniteClientException(msg, null, statusCode); }
/// <summary> /// Performs a send-receive operation. /// </summary> public T DoOutInOp <T>(ClientOp opId, Action <IBinaryStream> writeAction, Func <IBinaryStream, T> readFunc, Func <ClientStatus, string, T> errorFunc = null) { var requestId = Interlocked.Increment(ref _requestId); var resBytes = SendReceive(_socket, stream => { stream.WriteShort((short)opId); stream.WriteLong(requestId); if (writeAction != null) { writeAction(stream); } }); using (var stream = new BinaryHeapStream(resBytes)) { var resRequestId = stream.ReadLong(); Debug.Assert(requestId == resRequestId); var statusCode = (ClientStatus)stream.ReadInt(); if (statusCode == ClientStatus.Success) { return(readFunc != null?readFunc(stream) : default(T)); } var msg = BinaryUtils.Marshaller.StartUnmarshal(stream).ReadString(); if (errorFunc != null) { return(errorFunc(statusCode, msg)); } throw new IgniteClientException(msg, null, (int)statusCode); } }
/// <summary> /// Performs client protocol handshake. /// </summary> private void Handshake(IgniteClientConfiguration clientConfiguration, ClientProtocolVersion version) { bool auth = version.CompareTo(Ver110) >= 0 && clientConfiguration.UserName != null; // Send request. int messageLen; var buf = WriteMessage(stream => { // Handshake. stream.WriteByte(OpHandshake); // Protocol version. stream.WriteShort(version.Major); stream.WriteShort(version.Minor); stream.WriteShort(version.Maintenance); // Client type: platform. stream.WriteByte(ClientType); // Authentication data. if (auth) { var writer = BinaryUtils.Marshaller.StartMarshal(stream); writer.WriteString(clientConfiguration.UserName); writer.WriteString(clientConfiguration.Password); BinaryUtils.Marshaller.FinishMarshal(writer); } }, 12, out messageLen); SocketWrite(buf, messageLen); // Decode response. var res = ReceiveMessage(); using (var stream = new BinaryHeapStream(res)) { // Read input. var success = stream.ReadBool(); if (success) { if (version.CompareTo(Ver140) >= 0) { ServerNodeId = BinaryUtils.Marshaller.Unmarshal <Guid>(stream); } ServerVersion = version; return; } ServerVersion = new ClientProtocolVersion(stream.ReadShort(), stream.ReadShort(), stream.ReadShort()); var errMsg = BinaryUtils.Marshaller.Unmarshal <string>(stream); ClientStatusCode errCode = ClientStatusCode.Fail; if (stream.Remaining > 0) { errCode = (ClientStatusCode)stream.ReadInt(); } // Authentication error is handled immediately. if (errCode == ClientStatusCode.AuthenticationFailed) { throw new IgniteClientException(errMsg, null, ClientStatusCode.AuthenticationFailed); } // Re-try if possible. bool retry = ServerVersion.CompareTo(version) < 0 && ServerVersion.Equals(Ver100); if (retry) { Handshake(clientConfiguration, ServerVersion); } else { throw new IgniteClientException(string.Format( "Client handshake failed: '{0}'. Client version: {1}. Server version: {2}", errMsg, version, ServerVersion), null, errCode); } } }
/// <summary> /// Write object as a predefined type if possible. /// </summary> /// <param name="hdr">Header.</param> /// <param name="inStream">Input stream.</param> /// <param name="outStream">Output stream.</param> /// <param name="ctx">Context.</param> /// <returns><c>True</c> if was written.</returns> private bool WriteAsPredefined(byte hdr, BinaryHeapStream inStream, IBinaryStream outStream, Context ctx) { switch (hdr) { case BinaryTypeId.Byte: TransferBytes(inStream, outStream, 1); break; case BinaryTypeId.Short: TransferBytes(inStream, outStream, 2); break; case BinaryTypeId.Int: TransferBytes(inStream, outStream, 4); break; case BinaryTypeId.Long: TransferBytes(inStream, outStream, 8); break; case BinaryTypeId.Float: TransferBytes(inStream, outStream, 4); break; case BinaryTypeId.Double: TransferBytes(inStream, outStream, 8); break; case BinaryTypeId.Char: TransferBytes(inStream, outStream, 2); break; case BinaryTypeId.Bool: TransferBytes(inStream, outStream, 1); break; case BinaryTypeId.Decimal: TransferBytes(inStream, outStream, 4); // Transfer scale int magLen = inStream.ReadInt(); // Transfer magnitude length. outStream.WriteInt(magLen); TransferBytes(inStream, outStream, magLen); // Transfer magnitude. break; case BinaryTypeId.String: BinaryUtils.WriteString(BinaryUtils.ReadString(inStream), outStream); break; case BinaryTypeId.Guid: TransferBytes(inStream, outStream, 16); break; case BinaryTypeId.Timestamp: TransferBytes(inStream, outStream, 12); break; case BinaryTypeId.ArrayByte: TransferArray(inStream, outStream, 1); break; case BinaryTypeId.ArrayShort: TransferArray(inStream, outStream, 2); break; case BinaryTypeId.ArrayInt: TransferArray(inStream, outStream, 4); break; case BinaryTypeId.ArrayLong: TransferArray(inStream, outStream, 8); break; case BinaryTypeId.ArrayFloat: TransferArray(inStream, outStream, 4); break; case BinaryTypeId.ArrayDouble: TransferArray(inStream, outStream, 8); break; case BinaryTypeId.ArrayChar: TransferArray(inStream, outStream, 2); break; case BinaryTypeId.ArrayBool: TransferArray(inStream, outStream, 1); break; case BinaryTypeId.ArrayDecimal: case BinaryTypeId.ArrayString: case BinaryTypeId.ArrayGuid: case BinaryTypeId.ArrayTimestamp: int arrLen = inStream.ReadInt(); outStream.WriteInt(arrLen); for (int i = 0; i < arrLen; i++) { Mutate0(ctx, inStream, outStream, false, null); } break; case BinaryTypeId.ArrayEnum: case BinaryTypeId.Array: int type = inStream.ReadInt(); outStream.WriteInt(type); if (type == BinaryTypeId.Unregistered) { outStream.WriteByte(inStream.ReadByte()); // String header. BinaryUtils.WriteString(BinaryUtils.ReadString(inStream), outStream); // String data. } arrLen = inStream.ReadInt(); outStream.WriteInt(arrLen); for (int i = 0; i < arrLen; i++) { Mutate0(ctx, inStream, outStream, false, EmptyVals); } break; case BinaryTypeId.Collection: int colLen = inStream.ReadInt(); outStream.WriteInt(colLen); outStream.WriteByte(inStream.ReadByte()); for (int i = 0; i < colLen; i++) { Mutate0(ctx, inStream, outStream, false, EmptyVals); } break; case BinaryTypeId.Dictionary: int dictLen = inStream.ReadInt(); outStream.WriteInt(dictLen); outStream.WriteByte(inStream.ReadByte()); for (int i = 0; i < dictLen; i++) { Mutate0(ctx, inStream, outStream, false, EmptyVals); Mutate0(ctx, inStream, outStream, false, EmptyVals); } break; case BinaryTypeId.Binary: TransferArray(inStream, outStream, 1); // Data array. TransferBytes(inStream, outStream, 4); // Offset in array. break; case BinaryTypeId.Enum: TransferBytes(inStream, outStream, 8); // int typeId, int value. break; default: return(false); } return(true); }
/// <summary> /// Internal mutation routine. /// </summary> /// <param name="inStream">Input stream.</param> /// <param name="outStream">Output stream.</param> /// <param name="ctx">Context.</param> /// <param name="changeHash">WHether hash should be changed.</param> /// <param name="vals">Values to be replaced.</param> /// <returns>Mutated object.</returns> private void Mutate0(Context ctx, BinaryHeapStream inStream, IBinaryStream outStream, bool changeHash, IDictionary <int, BinaryBuilderField> vals) { int inStartPos = inStream.Position; int outStartPos = outStream.Position; byte inHdr = inStream.ReadByte(); if (inHdr == BinaryUtils.HdrNull) { outStream.WriteByte(BinaryUtils.HdrNull); } else if (inHdr == BinaryUtils.HdrHnd) { int inHnd = inStream.ReadInt(); int oldPos = inStartPos - inHnd; int newPos; if (ctx.OldToNew(oldPos, out newPos)) { // Handle is still valid. outStream.WriteByte(BinaryUtils.HdrHnd); outStream.WriteInt(outStartPos - newPos); } else { // Handle is invalid, write full object. int inRetPos = inStream.Position; inStream.Seek(oldPos, SeekOrigin.Begin); Mutate0(ctx, inStream, outStream, false, EmptyVals); inStream.Seek(inRetPos, SeekOrigin.Begin); } } else if (inHdr == BinaryUtils.HdrFull) { var inHeader = BinaryObjectHeader.Read(inStream, inStartPos); BinaryUtils.ValidateProtocolVersion(inHeader.Version); int hndPos; if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos)) { // Object could be cached in parent builder. BinaryBuilderField cachedVal; if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal)) { WriteField(ctx, cachedVal); } else { // New object, write in full form. var inSchema = BinaryObjectSchemaSerializer.ReadSchema(inStream, inStartPos, inHeader, _desc.Schema, _binary.Marshaller.Ignite); var outSchema = BinaryObjectSchemaHolder.Current; var schemaIdx = outSchema.PushSchema(); try { // Skip header as it is not known at this point. outStream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); if (inSchema != null) { foreach (var inField in inSchema) { BinaryBuilderField fieldVal; var fieldFound = vals.TryGetValue(inField.Id, out fieldVal); if (fieldFound && fieldVal == BinaryBuilderField.RmvMarker) { continue; } outSchema.PushField(inField.Id, outStream.Position - outStartPos); if (!fieldFound) { fieldFound = _parent._cache != null && _parent._cache.TryGetValue(inField.Offset + inStartPos, out fieldVal); } if (fieldFound) { WriteField(ctx, fieldVal); vals.Remove(inField.Id); } else { // Field is not tracked, re-write as is. inStream.Seek(inField.Offset + inStartPos, SeekOrigin.Begin); Mutate0(ctx, inStream, outStream, false, EmptyVals); } } } // Write remaining new fields. foreach (var valEntry in vals) { if (valEntry.Value == BinaryBuilderField.RmvMarker) { continue; } outSchema.PushField(valEntry.Key, outStream.Position - outStartPos); WriteField(ctx, valEntry.Value); } var flags = inHeader.IsUserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; if (inHeader.IsCustomDotNetType) { flags |= BinaryObjectHeader.Flag.CustomDotNetType; } // Write raw data. int outRawOff = outStream.Position - outStartPos; if (inHeader.HasRaw) { var inRawOff = inHeader.GetRawOffset(inStream, inStartPos); var inRawLen = inHeader.SchemaOffset - inRawOff; flags |= BinaryObjectHeader.Flag.HasRaw; outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inRawLen); } // Write schema int outSchemaOff = outRawOff; var schemaPos = outStream.Position; int outSchemaId; if (inHeader.IsCompactFooter) { flags |= BinaryObjectHeader.Flag.CompactFooter; } var hasSchema = outSchema.WriteSchema(outStream, schemaIdx, out outSchemaId, ref flags); if (hasSchema) { outSchemaOff = schemaPos - outStartPos; flags |= BinaryObjectHeader.Flag.HasSchema; if (inHeader.HasRaw) { outStream.WriteInt(outRawOff); } if (_desc.Schema.Get(outSchemaId) == null) { _desc.Schema.Add(outSchemaId, outSchema.GetSchema(schemaIdx)); } } var outLen = outStream.Position - outStartPos; var outHash = inHeader.HashCode; if (changeHash) { // Get from identity resolver. outHash = BinaryArrayEqualityComparer.GetHashCode(outStream, outStartPos + BinaryObjectHeader.Size, schemaPos - outStartPos - BinaryObjectHeader.Size); } var outHeader = new BinaryObjectHeader(inHeader.TypeId, outHash, outLen, outSchemaId, outSchemaOff, flags); BinaryObjectHeader.Write(outHeader, outStream, outStartPos); outStream.Seek(outStartPos + outLen, SeekOrigin.Begin); // seek to the end of the object } finally { outSchema.PopSchema(schemaIdx); } } } else { // Object has already been written, write as handle. outStream.WriteByte(BinaryUtils.HdrHnd); outStream.WriteInt(outStartPos - hndPos); } // Synchronize input stream position. inStream.Seek(inStartPos + inHeader.Length, SeekOrigin.Begin); } else { // Try writing as well-known type with fixed size. outStream.WriteByte(inHdr); if (!WriteAsPredefined(inHdr, inStream, outStream, ctx)) { throw new IgniteException("Unexpected header [position=" + (inStream.Position - 1) + ", header=" + inHdr + ']'); } } }
/// <summary> /// Performs client protocol handshake. /// </summary> private ClientFeatures Handshake(IgniteClientConfiguration clientConfiguration, ClientProtocolVersion version) { var hasAuth = version >= Ver110 && clientConfiguration.UserName != null; var hasFeatures = version >= Ver170; // Send request. int messageLen; var buf = WriteMessage(stream => { // Handshake. stream.WriteByte(OpHandshake); // Protocol version. stream.WriteShort(version.Major); stream.WriteShort(version.Minor); stream.WriteShort(version.Maintenance); // Client type: platform. stream.WriteByte(ClientType); // Writing features. if (hasFeatures) { BinaryUtils.Marshaller.Marshal(stream, w => w.WriteByteArray(ClientFeatures.AllFeatures)); } // Authentication data. if (hasAuth) { BinaryUtils.Marshaller.Marshal(stream, writer => { writer.WriteString(clientConfiguration.UserName); writer.WriteString(clientConfiguration.Password); }); } }, 12, out messageLen); SocketWrite(buf, messageLen); // Decode response. var res = ReceiveMessage(); using (var stream = new BinaryHeapStream(res)) { // Read input. var success = stream.ReadBool(); if (success) { BitArray featureBits = null; if (hasFeatures) { featureBits = new BitArray(BinaryUtils.Marshaller.Unmarshal <byte[]>(stream)); } if (version >= Ver140) { ServerNodeId = BinaryUtils.Marshaller.Unmarshal <Guid>(stream); } ServerVersion = version; _logger.Debug("Handshake completed on {0}, protocol version = {1}", _socket.RemoteEndPoint, version); return(new ClientFeatures(version, featureBits)); } ServerVersion = new ClientProtocolVersion(stream.ReadShort(), stream.ReadShort(), stream.ReadShort()); var errMsg = BinaryUtils.Marshaller.Unmarshal <string>(stream); ClientStatusCode errCode = ClientStatusCode.Fail; if (stream.Remaining > 0) { errCode = (ClientStatusCode)stream.ReadInt(); } _logger.Debug("Handshake failed on {0}, requested protocol version = {1}, " + "server protocol version = {2}, status = {3}, message = {4}", _socket.RemoteEndPoint, version, ServerVersion, errCode, errMsg); // Authentication error is handled immediately. if (errCode == ClientStatusCode.AuthenticationFailed) { throw new IgniteClientException(errMsg, null, ClientStatusCode.AuthenticationFailed); } // Retry if server version is different and falls within supported version range. var retry = ServerVersion != version && ServerVersion >= Ver100 && ServerVersion <= CurrentProtocolVersion; if (retry) { _logger.Debug("Retrying handshake on {0} with protocol version {1}", _socket.RemoteEndPoint, ServerVersion); return(Handshake(clientConfiguration, ServerVersion)); } throw new IgniteClientException(string.Format( "Client handshake failed: '{0}'. Client version: {1}. Server version: {2}", errMsg, version, ServerVersion), null, errCode); } }
/// <summary> /// Write object as a predefined type if possible. /// </summary> /// <param name="hdr">Header.</param> /// <param name="inStream">Input stream.</param> /// <param name="outStream">Output stream.</param> /// <param name="ctx">Context.</param> /// <returns><c>True</c> if was written.</returns> private bool WriteAsPredefined(byte hdr, BinaryHeapStream inStream, IBinaryStream outStream, Context ctx) { switch (hdr) { case BinaryUtils.TypeByte: TransferBytes(inStream, outStream, 1); break; case BinaryUtils.TypeShort: TransferBytes(inStream, outStream, 2); break; case BinaryUtils.TypeInt: TransferBytes(inStream, outStream, 4); break; case BinaryUtils.TypeLong: TransferBytes(inStream, outStream, 8); break; case BinaryUtils.TypeFloat: TransferBytes(inStream, outStream, 4); break; case BinaryUtils.TypeDouble: TransferBytes(inStream, outStream, 8); break; case BinaryUtils.TypeChar: TransferBytes(inStream, outStream, 2); break; case BinaryUtils.TypeBool: TransferBytes(inStream, outStream, 1); break; case BinaryUtils.TypeDecimal: TransferBytes(inStream, outStream, 4); // Transfer scale int magLen = inStream.ReadInt(); // Transfer magnitude length. outStream.WriteInt(magLen); TransferBytes(inStream, outStream, magLen); // Transfer magnitude. break; case BinaryUtils.TypeString: BinaryUtils.WriteString(BinaryUtils.ReadString(inStream), outStream); break; case BinaryUtils.TypeGuid: TransferBytes(inStream, outStream, 16); break; case BinaryUtils.TypeTimestamp: TransferBytes(inStream, outStream, 12); break; case BinaryUtils.TypeArrayByte: TransferArray(inStream, outStream, 1); break; case BinaryUtils.TypeArrayShort: TransferArray(inStream, outStream, 2); break; case BinaryUtils.TypeArrayInt: TransferArray(inStream, outStream, 4); break; case BinaryUtils.TypeArrayLong: TransferArray(inStream, outStream, 8); break; case BinaryUtils.TypeArrayFloat: TransferArray(inStream, outStream, 4); break; case BinaryUtils.TypeArrayDouble: TransferArray(inStream, outStream, 8); break; case BinaryUtils.TypeArrayChar: TransferArray(inStream, outStream, 2); break; case BinaryUtils.TypeArrayBool: TransferArray(inStream, outStream, 1); break; case BinaryUtils.TypeArrayDecimal: case BinaryUtils.TypeArrayString: case BinaryUtils.TypeArrayGuid: case BinaryUtils.TypeArrayTimestamp: case BinaryUtils.TypeArrayEnum: case BinaryUtils.TypeArray: int arrLen = inStream.ReadInt(); outStream.WriteInt(arrLen); for (int i = 0; i < arrLen; i++) { Mutate0(ctx, inStream, outStream, false, 0, null); } break; case BinaryUtils.TypeCollection: int colLen = inStream.ReadInt(); outStream.WriteInt(colLen); outStream.WriteByte(inStream.ReadByte()); for (int i = 0; i < colLen; i++) { Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); } break; case BinaryUtils.TypeDictionary: int dictLen = inStream.ReadInt(); outStream.WriteInt(dictLen); outStream.WriteByte(inStream.ReadByte()); for (int i = 0; i < dictLen; i++) { Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); } break; case BinaryUtils.TypeMapEntry: Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); Mutate0(ctx, inStream, outStream, false, 0, EmptyVals); break; case BinaryUtils.TypeBinary: TransferArray(inStream, outStream, 1); // Data array. TransferBytes(inStream, outStream, 4); // Offset in array. break; case BinaryUtils.TypeEnum: TransferBytes(inStream, outStream, 4); // Integer ordinal. break; default: return(false); } return(true); }