/** * <summary> * Wraps protocol message into a results bean.</summary> * * <param name="data">Protocol message that need to be wrapped.</param> * <returns>Wrapped message.</returns> */ private static GridClientResponse WrapResponse(ProtoResponse data) { GridClientResponse bean = new GridClientResponse(); //bean.RequestId = data.RequestId; //bean.ClientId = WrapGuid(data.ClientId); bean.Status = GridClientResponse.FindByCode(data.Status); if (data.HasErrorMessage) { bean.ErrorMessage = data.ErrorMessage; } if (data.HasResultBean) { bean.Result = WrapObject(data.ResultBean); } if (data.HasSessionToken) { bean.SessionToken = data.SessionToken.ToByteArray(); } return(bean); }
/** * <summary> * Handles incoming response message.</summary> * * <param name="msg">Incoming response message.</param> */ private void handleResponse(GridClientResponse msg) { Dbg.Assert(Thread.CurrentThread.Equals(rdr)); GridClientTcpRequestFuture fut; lock (pendingReqs) { if (!pendingReqs.TryGetValue(msg.RequestId, out fut)) { return; } } // Update authentication session token. if (msg.SessionToken != null) { sesTok = msg.SessionToken; } if (fut.State == GridClientTcpRequestFuture.INITIAL) { // If request initially failed due to authentication - try to re-authenticate session. if (msg.Status == GridClientResponseStatus.AuthFailure) { fut.State = GridClientTcpRequestFuture.AUTHORISING; sendCredentials(msg.RequestId); } else { finishRequest(fut, msg); } } else if (fut.State == GridClientTcpRequestFuture.AUTHORISING) { if (msg.Status == GridClientResponseStatus.Success) { // Send the original message under authorised session. fut.State = GridClientTcpRequestFuture.RETRY; fut.Message.SessionToken = sesTok; sendPacket(fut.Message); } else { // Let the request fail straight way. finishRequest(fut, msg); } } else // State == RETRY // Finish request with whatever server responded. { finishRequest(fut, msg); } }
/** * <summary> * Finishes user request to the grid.</summary> * * <param name="fut">Future used to pass result to the user.</param> * <param name="resp">Incoming response message.</param> */ private void finishRequest(GridClientFuture fut, GridClientResponse resp) { switch (resp.Status) { case GridClientResponseStatus.Success: fut.Done(resp.Result); break; case GridClientResponseStatus.Failed: var error = resp.ErrorMessage; if (error == null) { error = "Unknown server error"; } fut.Fail(() => { throw new GridClientException(error); }); break; case GridClientResponseStatus.AuthFailure: fut.Fail(() => { throw new GridClientAuthenticationException("Authentication failed (session expired?)" + " errMsg=" + resp.ErrorMessage + ", [srv=" + ServerAddress + "]"); }); U.Async(() => Close(false)); break; case GridClientResponseStatus.AuthorizationFailure: fut.Fail(() => { throw new GridClientException("Client authorization failed: " + resp.ErrorMessage); }); break; default: fut.Fail(() => { throw new GridClientException("Unknown server response status code: " + resp.Status); }); break; } pendingReqs.Remove(resp.RequestId); }
/** * <summary> * Wraps results bean into a protocol message.</summary> * * <param name="bean">Results bean that need to be wrapped.</param> * <returns>Wrapped message.</returns> */ private static ProtoResponse WrapResultBean(GridClientResponse bean) { ProtoResponse.Builder builder = ProtoResponse.CreateBuilder() //.SetRequestId(bean.RequestId) //.SetClientId(WrapGuid(bean.ClientId)) .SetStatus((int)bean.Status); if (bean.ErrorMessage != null) { builder.SetErrorMessage(bean.ErrorMessage); } if (bean.Result != null) { builder.SetResultBean(WrapObject(bean.Result)); } if (bean.SessionToken != null) { builder.SetSessionToken(ByteString.CopyFrom(bean.SessionToken)); } return(builder.Build()); }
/** <summary>Reader thread.</summary> */ private void readPackets() { try { bool running = true; while (running) { // Note that only this thread removes futures from map. // So if we see closed condition, it is safe to check map size since no more futures // will be added to the map. if (closed) { // Exit if either all requests processed or we do not wait for completion. if (!waitCompletion) { break; } lock (pendingReqs) { if (pendingReqs.Count == 0) { break; } } } // Header. int symbol; try { symbol = readByte(); } catch (TimeoutException) { checkPing(); continue; } // Connection closed. if (symbol == -1) { Dbg.WriteLine("Connection closed by remote host " + "[srvAddr=" + ServerAddress + ", symbol=" + symbol + "]"); break; } // Check for correct header. if ((byte)symbol != (byte)0x90) { Dbg.WriteLine("Failed to parse incoming message (unexpected header received, will close) " + "[srvAddr=" + ServerAddress + ", symbol=" + symbol + "]"); break; } // Packet. MemoryStream buf = new MemoryStream(); int len = 0; while (true) { try { symbol = readByte(); } catch (TimeoutException) { checkPing(); continue; } if (symbol == -1) { running = false; break; } byte b = (byte)symbol; buf.WriteByte(b); if (len == 0) { if (buf.Length == 4) { len = U.BytesToInt32(buf.ToArray(), 0); // Reset buffer. buf.SetLength(0); if (len == 0) { // Ping received. lastPingRcvTime = U.Now; break; } } } else { if (buf.Length == len) { if (len < 40) { Dbg.WriteLine("Invalid packet received [len=" + len + ", buf=" + buf + "]"); break; } buf.Position = 0; // Rewind buffer. byte[] head = new byte[40]; byte[] packet = new byte[len - head.Length]; buf.Read(head, 0, head.Length); buf.Read(packet, 0, packet.Length); GridClientResponse msg = marshaller.Unmarshal <GridClientResponse>(packet); msg.RequestId = U.BytesToInt64(head, 0); msg.ClientId = U.BytesToGuid(head, 8); msg.DestNodeId = U.BytesToGuid(head, 24); // Reset buffer. buf.SetLength(0); len = 0; lastPacketRcvTime = U.Now; handleResponse(msg); break; } } } } } catch (IOException e) { if (!closed) { Dbg.WriteLine("Failed to read data from remote host (will close connection)" + " [addr=" + ServerAddress + ", e=" + e.Message + "]"); } } catch (Exception e) { Dbg.WriteLine("Unexpected throwable in connection reader thread (will close connection)" + " [addr={0}, e={1}]", ServerAddress, e); } finally { U.Async(() => Close(false)); } }
/** * <summary> * Handle server response.</summary> * * <param name="args">Parameters map.</param> * <param name="fut">Future to use.</param> * <param name="str">Downloaded string response.</param> */ private void OnResponse(IDictionary <String, Object> args, GridClientFuture fut, String str) { try { JavaScriptSerializer s = new JavaScriptSerializer(); // Parse json response. var json = (IDictionary <String, Object>)s.Deserialize(str, typeof(Object)); // Recover status. GridClientResponseStatus statusCode = GridClientResponse.FindByCode((int)json["successStatus"]); // Retry with credentials, if authentication failed. if (statusCode == GridClientResponseStatus.AuthFailure) { // Reset session token. sessionToken = null; // Re-send request with credentials and without session token. str = LoadString(args, null); // Parse json response. json = (IDictionary <String, Object>)s.Deserialize(str, typeof(IDictionary <String, Object>)); // Recover status. statusCode = GridClientResponse.FindByCode((int)json["successStatus"]); } Object o; String errorMsg = null; if (json.TryGetValue("error", out o)) { errorMsg = (String)o; } if (String.IsNullOrEmpty(errorMsg)) { errorMsg = "Unknown server error"; } if (statusCode == GridClientResponseStatus.AuthFailure) { // Close this connection. Close(false); throw new GridClientAuthenticationException("Client authentication failed " + "[clientId=" + ClientId + ", srvAddr=" + ServerAddress + ", errMsg=" + errorMsg + ']'); } if (statusCode == GridClientResponseStatus.Failed) { throw new GridClientException(errorMsg); } if (statusCode == GridClientResponseStatus.AuthorizationFailure) { throw new GridClientException("Client authorization failed: " + errorMsg); } if (statusCode != GridClientResponseStatus.Success) { throw new GridClientException("Unsupported response status code: " + statusCode); } // Update session token only on success and auth-failed responses. if (json.TryGetValue("sessionToken", out o)) { sessionToken = o == null ? null : o.ToString(); } fut.Done(json["response"]); } catch (Exception e) { fut.Fail(() => { throw new GridClientException(e.Message, e); }); } finally { lock (pendingReqs) { pendingReqs.Remove(fut); } } }
/** <summary>Reader thread.</summary> */ private void readPackets() { try { bool running = true; byte[] lenByte = new byte[4]; byte[] head = new byte[40]; while (running) { // Note that only this thread removes futures from map. // So if we see closed condition, it is safe to check map size since no more futures // will be added to the map. if (closed) { // Exit if either all requests processed or we do not wait for completion. if (!waitCompletion) { break; } if (pendingReqs.Count == 0) { break; } } // Header. int symbol; try { if (lastReadTimedOut) { lastReadTimedOut = false; if (isSslStream) { // Recover SSL stream state after socket exception. skipSslDataRecordHeader(); } } symbol = inStream.ReadByte(); } catch (Exception e) { if (e.InnerException is SocketException) { e = e.InnerException; } var sockEx = e as SocketException; if (sockEx != null && sockEx.ErrorCode == 10060) { checkPing(); lastReadTimedOut = true; continue; } // All other exceptions are interpreted as stream ends. throw; } // Connection closed. if (symbol == -1) { Dbg.WriteLine("Connection closed by remote host " + "[srvAddr=" + ServerAddress + ", symbol=" + symbol + "]"); break; } // Check for correct header. if ((byte)symbol != (byte)0x90) { Dbg.WriteLine("Failed to parse incoming message (unexpected header received, will close) " + "[srvAddr=" + ServerAddress + ", symbol=" + symbol + "]"); break; } U.ReadFully(inStream, lenByte, 0, 4); int len = U.BytesToInt32(lenByte, 0); if (len == 0) { // Ping received. lastPingRcvTime = U.Now; continue; } if (len < 40) { Dbg.WriteLine("Invalid packet received [len=" + len + "]"); break; } U.ReadFully(inStream, head, 0, 40); long reqId = U.BytesToInt64(head, 0); Guid clientId = U.BytesToGuid(head, 8); Guid destNodeId = U.BytesToGuid(head, 24); byte[] msgBytes = new byte[len - 40]; U.ReadFully(inStream, msgBytes, 0, msgBytes.Length); GridClientResponse msg = marshaller.Unmarshal <GridClientResponse>(msgBytes); msg.RequestId = reqId; msg.ClientId = clientId; msg.DestNodeId = destNodeId; lastPacketRcvTime = U.Now; handleResponse(msg); } } catch (IOException e) { if (!closed) { Dbg.WriteLine("Failed to read data from remote host (will close connection)" + " [addr=" + ServerAddress + ", e=" + e.Message + "]"); } } catch (Exception e) { Dbg.WriteLine("Unexpected throwable in connection reader thread (will close connection)" + " [addr={0}, e={1}]", ServerAddress, e); } finally { U.Async(() => Close(false)); } }