/// <summary> /// Sends the request to the server. /// </summary> protected void SendRequest(DataPacket request) { request.Encode(); netStream.Write(request.Buffer, 0, request.BufferLength); if (CommLog != null) { CommLog.WriteAction(FunctionID.GetName(request.FunctionID)); CommLog.WriteAction(BuildWritingText(request.Buffer, 0, request.BufferLength)); } }
/// <summary> /// Sends the request to the server. /// </summary> protected void SendRequest(DataPacket request) { try { request.Encode(); netStream.Write(request.Buffer, 0, request.BufferLength); if (CommLog != null) { CommLog.WriteAction(FunctionID.GetName(request.FunctionID)); CommLog.WriteAction(BuildWritingText(request.Buffer, 0, request.BufferLength)); } } catch (IOException) { ClientState = ClientState.Error; throw; } }
/// <summary> /// Disconnects from the server. /// </summary> protected void Disconnect() { if (tcpClient != null) { CommLog?.WriteAction("Disconnect"); if (netStream != null) { ClearNetStream(netStream, inBuf); // to disconnect correctly netStream.Close(); netStream = null; } tcpClient.Close(); tcpClient = null; ClientState = ClientState.Disconnected; SessionID = 0; ServerName = ""; } }
/// <summary> /// Connects and authenticates with the server. /// </summary> protected void Connect() { // create connection tcpClient = new TcpClient { SendTimeout = ConnectionOptions.Timeout, ReceiveTimeout = ConnectionOptions.Timeout }; // connect CommLog?.WriteAction("Connect to " + ConnectionOptions.Host); if (IPAddress.TryParse(ConnectionOptions.Host, out IPAddress address)) { tcpClient.Connect(address, ConnectionOptions.Port); } else { tcpClient.Connect(ConnectionOptions.Host, ConnectionOptions.Port); } netStream = tcpClient.GetStream(); ClientState = ClientState.Connected; }
/// <summary> /// Receives a response from the server. /// </summary> protected DataPacket ReceiveResponse(DataPacket request) { DataPacket response = null; bool formatError = true; string errDescr = ""; int bytesToRead = HeaderLength + 2; int bytesRead; try { bytesRead = netStream.Read(inBuf, 0, bytesToRead); CommLog?.WriteAction(BuildReadingText(inBuf, 0, bytesToRead, bytesRead)); } catch (IOException) { ClientState = ClientState.Error; throw; } if (bytesRead == bytesToRead) { response = new DataPacket { TransactionID = BitConverter.ToUInt16(inBuf, 0), DataLength = BitConverter.ToInt32(inBuf, 2), SessionID = BitConverter.ToInt64(inBuf, 6), FunctionID = BitConverter.ToUInt16(inBuf, 14), Buffer = inBuf }; if (response.DataLength + 6 > inBuf.Length) { errDescr = Locale.IsRussian ? "длина данных слишком велика" : "data length is too big"; } else if (response.TransactionID != request.TransactionID) { errDescr = Locale.IsRussian ? "неверный идентификатор транзакции" : "incorrect transaction ID"; } else if (response.SessionID != SessionID && SessionID != 0) { errDescr = Locale.IsRussian ? "неверный идентификатор сессии" : "incorrect session ID"; } else if ((response.FunctionID & 0x7FFF) != request.FunctionID) { errDescr = Locale.IsRussian ? "неверный идентификатор функции" : "incorrect function ID"; } else { // read the rest of the data bytesToRead = response.DataLength - 10; bytesRead = ReadData(netStream, tcpClient.ReceiveTimeout, inBuf, HeaderLength + 2, bytesToRead); CommLog?.WriteAction(BuildReadingText(inBuf, HeaderLength + 2, bytesToRead, bytesRead)); if (bytesRead == bytesToRead) { formatError = false; responseDT = DateTime.UtcNow; // handle error response if ((response.FunctionID & 0x8000) > 0) { ErrorCode errorCode = (ErrorCode)inBuf[ArgumentIndex]; CommLog?.WriteError(errorCode.ToString()); throw new ProtocolException(errorCode); } } else { errDescr = Locale.IsRussian ? "не удалось прочитать все данные" : "unable to read all data"; } } } else { errDescr = Locale.IsRussian ? "не удалось прочитать заголовок пакета данных" : "unable to read data packet header"; } if (formatError) { throw new ScadaException(Locale.IsRussian ? "Некорректный формат данных, полученных от сервера: {0}" : "Incorrect format of data received from the server: {0}", errDescr); } return(response); }
/// <summary> /// Restores a connection with the server. /// </summary> protected void RestoreConnection() { DateTime utcNow = DateTime.UtcNow; bool connectNeeded = false; if (ClientState == ClientState.LoggedIn) { if (utcNow - responseDT > PingPeriod) { try { // check connection DataPacket request = CreateRequest(FunctionID.GetStatus, 10); SendRequest(request); ReceiveResponse(request); } catch { connectNeeded = true; } } } else if (utcNow - connAttemptDT > ReconnectPeriod) { connectNeeded = true; } try { if (connectNeeded) { connAttemptDT = utcNow; Disconnect(); Connect(); GetSessionInfo(out long sessionID, out string serverName); SessionID = sessionID; ServerName = serverName; Login(ConnectionOptions.Username, ConnectionOptions.Password, out bool loggedIn, out int userID, out int roleID, out string errMsg); UserID = userID; RoleID = roleID; if (loggedIn) { ClientState = ClientState.LoggedIn; CommLog?.WriteAction("User is logged in"); } else { throw new ScadaException(errMsg); } } else if (ClientState == ClientState.LoggedIn) { ClearNetStream(netStream, inBuf); } else { throw new ScadaException(Locale.IsRussian ? "Клиент не вошёл в систему. Попробуйте позже." : "Client is not logged in. Try again later."); } } catch { ClientState = ClientState.Error; throw; } }
/// <summary> /// Restores a connection with the server. /// </summary> protected void RestoreConnection() { DateTime utcNow = DateTime.UtcNow; bool connectNeeded = false; if (ClientState == ClientState.LoggedIn) { if (utcNow - responseDT > PingPeriod) { try { // check connection DataPacket request = CreateRequest(FunctionID.GetStatus, 10); SendRequest(request); ReceiveResponse(request); } catch { connectNeeded = true; } } } else if (utcNow - connAttemptDT > ReconnectPeriod) { connectNeeded = true; } try { if (connectNeeded) { connAttemptDT = utcNow; Disconnect(); Connect(); GetSessionInfo(out long sessionID, out ushort protocolVersion, out string serverName); SessionID = sessionID; ServerName = serverName; if (protocolVersion != ProtocolVersion) { throw new ScadaException(Locale.IsRussian ? "Несовместимая версия протокола." : "Incompatible protocol version."); } Login(out bool loggedIn, out _, out _, out string errorMessage); if (loggedIn) { ClientState = ClientState.LoggedIn; CommLog?.WriteAction("User is logged in"); } else { throw new ScadaException(errorMessage); } } else if (ClientState == ClientState.LoggedIn) { ClearNetStream(netStream, inBuf); } else { throw new ScadaException(Locale.IsRussian ? "Клиент не вошёл в систему. Попробуйте позже." : "Client is not logged in. Try again later."); } } catch { ClientState = ClientState.Error; throw; } }