/// <summary> /// Передать команду ТУ подключенным клиентам /// </summary> public void PassCommand(Command cmd) { lock (cmdBuf) { if (cmd != null) { cmd.PrepareCmdData(); cmdBuf.Add(cmd); } } }
/// <summary> /// Обработать полученную команду /// </summary> private void ProcCommand(ClientInfo client, byte cmd, int cmdLen) { bool sendResp = true; // отправить ответ на команду int respDataLen = 0; // длина данных ответа на команду byte[] extraData = null; // дополнительные данные ответа switch (cmd) { case 0x01: // проверка имени и пароля int userNameLen = inBuf[3]; string userName = Encoding.Default.GetString(inBuf, 4, userNameLen); string password = Encoding.Default.GetString(inBuf, 5 + userNameLen, inBuf[4 + userNameLen]); bool pwdIsEmpty = string.IsNullOrEmpty(password); int roleID; bool checkOk = CheckUser(userName, password, out roleID); if (client.Authenticated) { if (pwdIsEmpty) { string checkOkStr = checkOk ? (Localization.UseRussian ? "успешно" : "success") : (Localization.UseRussian ? "ошибка" : "error"); appLog.WriteAction(string.Format(Localization.UseRussian ? "Получение роли пользователя {0}. Результат: {1}" : "Get user {0} role. Result: {1}", userName, checkOkStr), Log.ActTypes.Action); } else { string checkOkStr = checkOk ? (Localization.UseRussian ? "верно" : "passed") : (Localization.UseRussian ? "неверно" : "failed"); appLog.WriteAction(string.Format(Localization.UseRussian ? "Проверка имени и пароля пользователя {0}. Результат: {1}" : "Check user {0} name and password. Result: {1}", userName, checkOkStr), Log.ActTypes.Action); } } else { if (checkOk && roleID != BaseValues.Roles.Disabled && !pwdIsEmpty) { client.Authenticated = true; client.UserName = userName; client.UserRoleID = roleID; appLog.WriteAction(string.Format(Localization.UseRussian ? "Пользователь {0} успешно аутентифицирован" : "The user {0} is successfully authenticated", userName), Log.ActTypes.Action); } else { client.ActivityDT = DateTime.MinValue; // для отключения клиента после отправки ответа appLog.WriteAction(string.Format(Localization.UseRussian ? "Неудачная попытка аутентификации пользователя {0}" : "Unsuccessful attempt to authenticate the user {0}", userName), Log.ActTypes.Action); } } respDataLen = 1; outBuf[3] = (byte)roleID; break; case 0x02: // запрос состояния сервера (ping) respDataLen = 1; outBuf[3] = mainLogic.ServerIsReady ? (byte)1 : (byte)0; break; case 0x03: // запись текущего среза if (client.UserRoleID == BaseValues.Roles.App) { int cnlCnt = BitConverter.ToUInt16(inBuf, 3); SrezTableLight.Srez srez = new SrezTableLight.Srez(DateTime.MinValue, cnlCnt); for (int i = 0, j = 5; i < cnlCnt; i++, j += 14) { srez.CnlNums[i] = (int)BitConverter.ToUInt32(inBuf, j); srez.CnlData[i] = new SrezTableLight.CnlData( BitConverter.ToDouble(inBuf, j + 4), BitConverter.ToUInt16(inBuf, j + 12)); } outBuf[3] = mainLogic.ProcCurData(srez) ? (byte)1 : (byte)0; } else { outBuf[3] = 0; } respDataLen = 1; break; case 0x04: // запись архивного среза if (client.UserRoleID == BaseValues.Roles.App) { DateTime dateTime = Arithmetic.DecodeDateTime(BitConverter.ToDouble(inBuf, 3)); int cnlCnt = BitConverter.ToUInt16(inBuf, 11); SrezTableLight.Srez srez = new SrezTableLight.Srez(dateTime, cnlCnt); for (int i = 0, j = 13; i < cnlCnt; i++, j += 14) { srez.CnlNums[i] = (int)BitConverter.ToUInt32(inBuf, j); srez.CnlData[i] = new SrezTableLight.CnlData( BitConverter.ToDouble(inBuf, j + 4), BitConverter.ToUInt16(inBuf, j + 12)); } outBuf[3] = mainLogic.ProcArcData(srez) ? (byte)1 : (byte)0; } else { outBuf[3] = 0; } respDataLen = 1; break; case 0x05: // запись события if (client.UserRoleID == BaseValues.Roles.App) { EventTableLight.Event ev = new EventTableLight.Event(); ev.DateTime = Arithmetic.DecodeDateTime(BitConverter.ToDouble(inBuf, 3)); ev.ObjNum = BitConverter.ToUInt16(inBuf, 11); ev.KPNum = BitConverter.ToUInt16(inBuf, 13); ev.ParamID = BitConverter.ToUInt16(inBuf, 15); ev.CnlNum = (int)BitConverter.ToUInt32(inBuf, 17); ev.OldCnlVal = BitConverter.ToDouble(inBuf, 21); ev.OldCnlStat = BitConverter.ToUInt16(inBuf, 29); ev.NewCnlVal = BitConverter.ToDouble(inBuf, 31); ev.NewCnlStat = BitConverter.ToUInt16(inBuf, 39); ev.Checked = BitConverter.ToBoolean(inBuf, 41); ev.UserID = BitConverter.ToUInt16(inBuf, 42); int evDescrLen = inBuf[44]; int evDataLen = inBuf[45 + evDescrLen]; ev.Descr = Encoding.Default.GetString(inBuf, 45, evDescrLen); ev.Data = Encoding.Default.GetString(inBuf, 46 + evDescrLen, evDataLen); outBuf[3] = mainLogic.ProcEvent(ev) ? (byte)1 : (byte)0; } else { outBuf[3] = 0; } respDataLen = 1; break; case 0x06: // команда ТУ bool cmdProcOk = false; // команда обработана успешно if (client.UserRoleID == BaseValues.Roles.Admin || client.UserRoleID == BaseValues.Roles.Dispatcher || client.UserRoleID == BaseValues.Roles.App) { int cmdUserID = BitConverter.ToUInt16(inBuf, 3); byte cmdTypeID = inBuf[5]; int ctrlCnlNum = BitConverter.ToUInt16(inBuf, 6); MainLogic.CtrlCnl ctrlCnl = mainLogic.GetCtrlCnl(ctrlCnlNum); string notFoundStr = ctrlCnl == null ? Localization.UseRussian ? " (не найден)" : " (not found)" : ""; appLog.WriteAction(string.Format(Localization.UseRussian ? "Команда ТУ: канал упр. = {0}{1}, ид. польз. = {2}" : "Command: out channel = {0}{1}, user ID = {2}", ctrlCnlNum, notFoundStr, cmdUserID), Log.ActTypes.Action); if (ctrlCnl != null) { // создание команды ТУ Command ctrlCmd = new Command(cmdTypeID); ctrlCmd.CmdData = new byte[BitConverter.ToUInt16(inBuf, 8)]; Array.Copy(inBuf, 10, ctrlCmd.CmdData, 0, ctrlCmd.CmdData.Length); if (cmdTypeID == BaseValues.CmdTypes.Standard || cmdTypeID == BaseValues.CmdTypes.Binary) { ctrlCmd.KPNum = (ushort)ctrlCnl.KPNum; ctrlCmd.CmdNum = (ushort)ctrlCnl.CmdNum; if (cmdTypeID == BaseValues.CmdTypes.Standard && ctrlCmd.CmdData.Length == 8) ctrlCmd.CmdVal = BitConverter.ToDouble(ctrlCmd.CmdData, 0); } else if (cmdTypeID == BaseValues.CmdTypes.Request) { ctrlCmd.KPNum = BitConverter.ToUInt16(inBuf, 10); } // обработка команды ТУ bool passToClients; mainLogic.ProcCommand(ctrlCnl, ctrlCmd, cmdUserID, out passToClients); // передача команды ТУ подключенным клиентам if (passToClients) { ctrlCmd.PrepareCmdData(); foreach (ClientInfo cl in clients) if (cl.UserRoleID == BaseValues.Roles.App) cl.CmdList.Add(ctrlCmd); } else { appLog.WriteAction(Localization.UseRussian ? "Команда ТУ отменена" : "Command is canceled", Log.ActTypes.Action); } cmdProcOk = true; } } respDataLen = 1; outBuf[3] = cmdProcOk ? (byte)1 : (byte)0; break; case 0x07: // запрос команды ТУ if (client.UserRoleID == BaseValues.Roles.App && client.CmdList.Count > 0) { Command ctrlCmd = client.CmdList[0]; int cmdDataLen = ctrlCmd.CmdData == null ? 0 : ctrlCmd.CmdData.Length; respDataLen = 7 + cmdDataLen; outBuf[3] = (byte)(cmdDataLen % 256); outBuf[4] = (byte)(cmdDataLen / 256); outBuf[5] = (byte)ctrlCmd.CmdTypeID; outBuf[6] = (byte)(ctrlCmd.KPNum % 256); outBuf[7] = (byte)(ctrlCmd.KPNum / 256); outBuf[8] = (byte)(ctrlCmd.CmdNum % 256); outBuf[9] = (byte)(ctrlCmd.CmdNum / 256); if (cmdDataLen > 0) Array.Copy(ctrlCmd.CmdData, 0, outBuf, 10, cmdDataLen); // удаление команды ТУ из списка команд клиента client.CmdList.RemoveAt(0); } else { respDataLen = 2; outBuf[3] = 0; outBuf[4] = 0; } break; case 0x08: // открытие и чтение из файла int readCnt = 0; bool readOk = false; if (client.Authenticated) { client.CloseFile(); try { client.Dir = (Dirs)inBuf[3]; } catch { client.Dir = Dirs.Cur; } int fileNameLen = inBuf[4]; client.FileName = Encoding.Default.GetString(inBuf, 5, fileNameLen); string fullFileName = GetFullFileName(client.Dir, client.FileName); int count = BitConverter.ToUInt16(inBuf, 5 + fileNameLen); if (settings.DetailedLog) appLog.WriteAction(string.Format(Localization.UseRussian ? "Открытие файла {0}" : "Opening file {0}", fullFileName), Log.ActTypes.Action); try { if (File.Exists(fullFileName)) { client.FileStream = new FileStream(fullFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); readCnt = client.FileStream.Read(outBuf, 6, count); readOk = true; } else { appLog.WriteAction(string.Format(Localization.UseRussian ? "Файл {0} не найден." : "File {0} not found.", client.FullFileNameInfo), Log.ActTypes.Error); } } catch (Exception ex) { appLog.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при работе с файлом {0}: {1}" : "Error working with the file {0}: {1}", client.FullFileNameInfo, ex.Message), Log.ActTypes.Exception); } finally { if (readCnt < count) client.CloseFile(); } } respDataLen = 3 + readCnt; outBuf[3] = readOk ? (byte)1 : (byte)0; outBuf[4] = (byte)(readCnt % 256); outBuf[5] = (byte)(readCnt / 256); break; case 0x09: // перемещение позиции чтения из файла long pos = 0; bool seekOk = false; if (client.Authenticated && client.FileStream != null) { SeekOrigin origin; try { origin = (SeekOrigin)inBuf[3]; } catch { origin = SeekOrigin.Begin; } long offset = BitConverter.ToUInt32(inBuf, 4); try { pos = client.FileStream.Seek(offset, origin); seekOk = true; } catch (Exception ex) { appLog.WriteAction("Ошибка при работе с файлом " + client.FullFileNameInfo + ": " + ex.Message, Log.ActTypes.Exception); } } respDataLen = 5; outBuf[3] = seekOk ? (byte)1 : (byte)0; Array.Copy(BitConverter.GetBytes((uint)pos), 0, outBuf, 4, 4); break; case 0x0A: // чтение из файла readCnt = 0; if (client.Authenticated && client.FileStream != null) { int count = BitConverter.ToUInt16(inBuf, 3); try { readCnt = client.FileStream.Read(outBuf, 5, count); } catch (Exception ex) { appLog.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при работе с файлом {0}: {1}" : "Error working with the file {0}: {1}", client.FullFileNameInfo, ex.Message), Log.ActTypes.Exception); } finally { if (readCnt < count) client.CloseFile(); } } respDataLen = 2 + readCnt; outBuf[3] = (byte)(readCnt % 256); outBuf[4] = (byte)(readCnt / 256); break; case 0x0B: // закрытие файла if (client.Authenticated && client.FileStream != null) { client.CloseFile(); outBuf[3] = 1; } else { outBuf[3] = 0; } respDataLen = 1; break; case 0x0C: // запрос времени изменения файлов int fileCnt = inBuf[3]; outBuf[3] = inBuf[3]; for (int i = 0, j = 4, k = 4; i < fileCnt; i++, k += 8) { Dirs dir; try { dir = (Dirs)inBuf[j++]; } catch { dir = Dirs.Cur; } int fileNameLen = inBuf[j++]; string fileName = Encoding.Default.GetString(inBuf, j, fileNameLen); string fullFileName = GetFullFileName(dir, fileName); j += fileNameLen; if (settings.DetailedLog) appLog.WriteAction(string.Format(Localization.UseRussian ? "Получение времени изменения файла {0}" : "Obtaining the modification time of the file {0}", fullFileName), Log.ActTypes.Action); double fileModTime; try { fileModTime = File.Exists(fullFileName) ? Arithmetic.EncodeDateTime(File.GetLastWriteTime(fullFileName)) : 0; } catch { fileModTime = 0; } Array.Copy(BitConverter.GetBytes(fileModTime), 0, outBuf, k, 8); } respDataLen = 1 + 8 * fileCnt; break; case 0x0D: // запрос данных из таблицы среза byte srezTypeNum = inBuf[3]; MainLogic.SrezTypes srezType; DateTime srezDate; if (srezTypeNum == 0x01) { srezType = MainLogic.SrezTypes.Cur; srezDate = DateTime.MinValue; } else { srezType = srezTypeNum == 0x02 ? MainLogic.SrezTypes.Hour : MainLogic.SrezTypes.Min; srezDate = new DateTime(inBuf[4] + 2000, inBuf[5], inBuf[6]); } int cnlNumCnt = BitConverter.ToUInt16(inBuf, 7); int[] cnlNums = new int[cnlNumCnt]; for (int i = 0, j = 9; i < cnlNumCnt; i++, j += 4) cnlNums[i] = (int)BitConverter.ToUInt32(inBuf, j); if (settings.DetailedLog) { string srezTypeStr; if (srezType == MainLogic.SrezTypes.Cur) srezTypeStr = Localization.UseRussian ? "текущие" : "current"; else if (srezType == MainLogic.SrezTypes.Min) srezTypeStr = Localization.UseRussian ? "минутные" : "minute"; else srezTypeStr = Localization.UseRussian ? "часовые" : "hourly"; appLog.WriteAction(string.Format(Localization.UseRussian ? "Запрос данных. Тип: {0}. Дата: {1}. Каналы: {2}" : "Data request. Type: {0}. Date: {1}. Channels: {2}", srezTypeStr, srezDate.ToString("d", Localization.Culture), string.Join(", ", cnlNums)), Log.ActTypes.Action); } SrezTableLight srezTable = mainLogic.GetSrezTable(srezDate, srezType, cnlNums); int srezCnt = srezTable == null ? 0 : srezTable.SrezList.Count; outBuf[5] = (byte)(srezCnt % 256); outBuf[6] = (byte)(srezCnt / 256); extraData = new byte[srezCnt * (10 * cnlNumCnt + 8)]; for (int i = 0, j = 0; i < srezCnt; i++) { SrezTableLight.Srez srez = srezTable.SrezList.Values[i]; Array.Copy(BitConverter.GetBytes(Arithmetic.EncodeDateTime(srez.DateTime)), 0, extraData, j, 8); j += 8; for (int k = 0; k < cnlNumCnt; k++) { SrezTable.CnlData cnlData = srez.CnlData[k]; Array.Copy(BitConverter.GetBytes(cnlData.Val), 0, extraData, j, 8); j += 8; extraData[j++] = (byte)(cnlData.Stat % 256); extraData[j++] = (byte)(cnlData.Stat / 256); } } respDataLen = 2 + extraData.Length; break; case 0x0E: // квитирование события if (client.Authenticated) { int evUserID = BitConverter.ToUInt16(inBuf, 3); DateTime evDate = new DateTime(inBuf[5] + 2000, inBuf[6], inBuf[7]); int evNum = BitConverter.ToUInt16(inBuf, 8); outBuf[3] = mainLogic.CheckEvent(evDate, evNum, evUserID) ? (byte)1 : (byte)0; } else { outBuf[3] = 0; } respDataLen = 1; break; } // передача ответа на команду if (sendResp) { if (cmd == 0x0D) { int respLen = 5 + respDataLen; Array.Copy(BitConverter.GetBytes((uint)respLen), 0, outBuf, 0, 4); outBuf[4] = cmd; client.NetStream.Write(outBuf, 0, 7); } else { int respLen = 3 + respDataLen; Array.Copy(BitConverter.GetBytes((ushort)respLen), 0, outBuf, 0, 2); outBuf[2] = cmd; client.NetStream.Write(outBuf, 0, respLen); } if (extraData != null && extraData.Length > 0) client.NetStream.Write(extraData, 0, extraData.Length); } }