コード例 #1
0
ファイル: Comm.cs プロジェクト: NoExceptions/scada
 /// <summary>
 /// Передать команду ТУ подключенным клиентам
 /// </summary>
 public void PassCommand(Command cmd)
 {
     lock (cmdBuf)
     {
         if (cmd != null)
         {
             cmd.PrepareCmdData();
             cmdBuf.Add(cmd);
         }
     }
 }
コード例 #2
0
ファイル: Comm.cs プロジェクト: raydtang/scada
        /// <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);
            }
        }