Telegrambot для слежения за майнером








Исходники в конце текста.


Здравствуйте.

В сети встречается уже не мало программ для управления майнерами через мессенджер Telegram с помощью ботов. Я решил присоединиться к этому направлению и написать свой сервер-бот — teleminerstd. Он очень простой и вся его работа сводится к тому, чтоб пересылать сообщения от майнера (те, что вы видите в терминале) вашему Телеграмботу. Отправку сообщений можно включать и отключать командами посылаемыми в Telegram, а так же ребутить или выключать комп/ферму.
В качестве доп. функций, умеет показывать курсы криптовалют.

Наглядная схема:




Сервер teleminerstd написан (на СИ и не потребляет практически никаких ресурсов) для Linux и работает через Webhook (то есть получает уведомления от Telegram автоматически), поэтому понадобится белый ip.

Работает следующим образом: в конфигурационный файл программы вписываете команду запуска Вашего майнера (работает с майнерами EWBF's CUDA Zcash miner и nheqminer, с другими не пробовал, но по идее должно работать) и стартуете teleminerstd. Teleminerstd запускает Ваш майнер, перехватывает его данные и по команде отправляет их в Telegram. Если в майнере возникает какая-либо ошибка, то она автоматически (без запроса) отправляется в Telegram.





Открываете приложение Telegram на вашем смартфоне, отправляете боту команду (vkldat) и любуетесь сообщениями от майнера.





Далее подробно обо всём…




Установите приложение Telegram на компьютер или смартфон.


Теперь нужно создать Телеграмбота, подготовить ssl-сертификат и установить Webhook. Весь этот несложный процесс я подробно описал в соседней статье, начиная отсюда и до фразы — «Всё что касается Telegram мы сделали…».




Наконец пришло время заняться программой teleminerstd. В домашней папке создайте папку teleminer и перейдите в неё:

mkdir teleminer && cd teleminer


Скачайте программу и конфиг-файл:

wget https://istarik.ru/file/teleminerstd


wget https://istarik.ru/file/teleminerstd.conf


А так же крохотную библиотеку:

wget https://istarik.ru/file/line_buffer.so

Она нужна для отключения буферизации вывода сообщений майнера.

Дайте программе все права:

sudo chmod 777 ./teleminerstd


И наконец, скопируйте в эту же папку созданный Вами файл cert.pem.

В итоге, в папке teleminer у Вас будут четыре файла — teleminerstd, teleminerstd.conf, line_buffer.so, cert.pem.



Наглядный конфиг-файл

port=8443
token=703562402:AAEoqwe5ghP9_ccbXreHsDD1n1m56Nwer1P
pminer=/home/dima/miner/miner --server zec.suprnova.cc --user Dimon.dimka --pass wor789rtyu --port 2142 --pec
globchatid=
data_on=vkldat
data_off=otkldat
all_off=otklall
count_dat=20
reb_komp=KfErEstDim41g
off_komp=zSDimErPst35F
rest_mainer=AsDaErEsSfW
comamd_info=rEsSfWKfErQ

В конце строк не оставляйте пробелов и соблюдайте указанный синтаксис.

В процессе разъяснения я буду использовать команды из выше приведённого конфига.


port=впишите порт, который указывали при установке Webhook'а. Не забудьте пробросить его на роутере.

token=Ваш токен.

pminer=путь к майнеру вместе с аргументами.
Если запускаете nheqminer или Claymore's, тогда в конце команды впишите такую конструкцию — 2>&1 (Это перенаправление вывода.)
(/home/dima/nheqminer -l zec.suprnova.cc:2142 -u Dimon.dimka -p wor789rtyu -t 2 2>&1).

(/home/dima/Claymore/zecminer64 2>&1).

globchatid= — пока ничего не пишите.

data_on=команда включающая отправку всех сообщений от майнера в Телеграм.

data_off=команда отключающая отправку сообщений от майнера, кроме сообщений сигнализирующих об ошибках.

all_off=команда отключающая вообще все сообщения от майнера. Отменяется командой vkldat.
Команды можете придумать любые (желательно посложнее), но только английскими буквами и не больше 14 символов.

count_dat=количество сообщений, которые будут отправлены после команды vkldat. Можно вписать любое число. Если хотите чтоб сообщения отсылались постоянно, то впишите 99000000, однако мне кажется это излишним
Тем более, как было замечено, если заваливать Telegram шквалом сообщений, то время от времени, его сервер «берёт таймаут» и не принимает соединение в течении пары минут, после чего работа возобновляется. При этом в логе ошибок (см.ниже) появится запись — «Error: connect».

reb_komp=это команда для перезагрузки компьютера/фермы, поэтому нужно обязательно придумать какую-нибудь хитрую и длинную (но не больше 14 символов) фразу, а то вдруг кто-нибудь найдёт вашего бота и начнёт ему что-то писать.

off_komp=эта команда выключает компьютер/ферму (команда должна быть хитрая и длинная).

rest_mainer=эта команда служит для рестарта майнера, на тот случай если он «упадёт (опять же, команда должна быть хитрая и длинная).

comamd_info=эта команда тоже должна быть секретная, она выводит список всех команд. Так что нужно запоминать только её.






После заполнения конфиг-файла можно запустить teleminerstd

sudo ./teleminerstd

Для остановки сервера используйте только — Ctrl + c. Иначе при следующем запуске, программа не сможет забиндиться.


После старта программа покажет то, что прочитала из конфига, а потом побегут строки майнера:



Теперь в Телеграме кликните своего бота, нажмите START и отправьте букву t. Если всё работает, то в ответ Вы получите слово TEST.




В терминале среди прочих строк будет Chat_id:617455910 (у вас будет другое число):



Это ID Вашего клиента. Его нужно вписать в конфиг-файл — globchatid=617455910

Тут требуется небольшое пояснение: когда Вы посылаете какую-либо команду, вместе с командой сервер получает id клиента, которому нужно отправить данные. Однако предположим, что если teleminerstd добавлен в автозагрузку, то после ребута фермы он не будет знать кому отправлять данные. Вот тут то и понадобится id вашего клиента записанный конфиге.
Если в процессе работы Вы будете отправлять команды с разных клиентов, тогда id будет меняться внутри программы.



Теперь при старте, в Telegram будет отправлено сообщение „START SYSTEM“…




… а следом побегут строки от майнера:



Строк будет выведено столько, сколько указано в конфиге (count_dat). Зачастую строки идут не по порядку, но это происходит тогда, когда единовременно отправляется много данных.



Далее попробуйте командами vkldat и otkldat включать и отключать вывод данных в Telegram:




Если не посылать команду otkldat, то (как уже выше написано) будет выведено столько строк, сколько указано в конфиге.



Теперь намеренно сделайте ошибку в конфиге, в адресе пула (zec.prnova.cc) и перезапустите teleminerstd:





Майнер будет запущен, но выдав ошибку тут же „самоубьется“ (это касается EWBF's Zcash CUDA miner, другие майнеры могут продолжать работу и слать ошибки). Teleminerstd отправит сообщения о происходящих событиях Telegramу и будет ожидать дальнейших команд, например, рестарта майнера или ребута фермы.




Разные майнеры по разному и с разной частотой выдают ошибки и варнинги, могут выдать одну ошибку и остановиться или продолжать нормальную работу, а могут работать и сыпать ошибки непрерывно. Поскольку сообщения об ошибках отправляются автоматически, (то есть даже при „otkldat“), это может принести дискомфорт. Для этого у программы есть счётчик ошибок, который при превышений числа 10, останавливает отправку и пишет „END MSG ERROR“.




После этого, если счётчик не будет обнулён, то запустится таймер, который будет отправлять по одной ошибке с интервалом не менее 10 минут.

Чтобы обнулить счётчик ошибок, нужно послать ту же команду, что и для отправки всех сообщений (»vkldat"), а если хотите отключить вообще любые сообщения, тогда отправьте команду («otklall»).


На все полученные команды, teleminerstd отвечает соответствующими сообщениями.



Свои ошибки teleminerstd пишет в файл — Errteleminerstd.log, который создаётся в папке вместе с программой и очищается при превышении 4Кб.
Помимо ошибок, в этот файл записываются некоторые ответственные действия, например команды выключения или перезагрузки (Error: Not error, received command REBOOT).




Дополнительные функции

С помощью команды rate,coin можно узнать курс какой-либо криптовалюты. После слова rate,, через запятую и без пробелов, впишите название интересующей монеты.
Например bitcoin или ethereum:



Ссылка ведёт на сайт с графиками.


В терминале это тоже отобразится:



Как видно из картинки, инфа берётся с сайта coinmarketcap.com, они предоставляют API, поэтому удобно.
Под спойлером список валют, взятый отсюда.

названия крипты
Вначале идёт популярная. Ешё болше названий смотрите по ссылке выше.

bitcoin, ethereum, ripple, litecoin, ethereum-classic, nem, dash, iota, bitshares, monero, 
stratis, zcash, golem-network-tokens, siacoin, steem, waves, bytecoin-bcn, iconomi, antshares, 
bitconnect, stellar, dogecoin, augur, lisk, gamecredits, factom, gnosis-gno, ardor, 
maidsafecoin, byteball, decred, veritaseum, digibyte, komodo, digixdao, nxt, 
basic-attention-token, tether, firstblood, mobilego, bancor, singulardtv, syscoin, pivx, 
bitcoindark, mcap, aragon, round, emercoin, peercoin, ubiq, lykke, numeraire, cloakcoin, 
ark, rlc, leocoin, reddcoin, quantum-resistant-ledger, storjcoin-x, asch, melon, nexus, synereo, 
library-credit, bitbay, peerplays-ppy, wings, edgeless, verge, omni, namecoin, counterparty, 
mysterium, gulden, monacoin, blackcoin, obits, elastic, xaurum, zcoin, burst, viacoin, vslice, 
ion, vertcoin, earthcoin, humaniq, cofound-it, ybcoin, blocknet, nav-coin, etheroll, trust, 
gridcoin, potcoin, mooncoin, luckchain, expanse, e-dinar-coin, tokencard, quantum, guppy, taas, 
radium, shift, neoscoin, bitcoin-plus, iocoin, skycoin, crown, digitalnote, energycoin, novacoin, 
nexium, bcap, worldcoin, dnotes, databits, unity-ingot, monetaryunit, lomocoin, primecoin, 
swarm-city, chronobank, heat-ledger, mergecoin, foldingcoin, infinitecoin, patientory, feathercoin, 
quark, einsteinium, voxels, vpncoin, e-coin, espers, vericoin, rubycoin, golos, faircoin, 
bitcrystals, firstcoin, clams, agoras-tokens, sibcoin, pluton, pepe-cash, bitcny, florincoin, megacoin, 
salus, xtrabytes, waves-community-token, belacoin, cryptonite, pascal-coin, eccoin, bankcoin, 
gambit, zencash, safe-exchange-coin, aeon, bitshares-music, dubaicoin-dbix, circuits-of-value, 
solarcoin, sphere, zccoin, bitland, pinkcoin, lunyr, okcash, maxcoin, spreadcoin, bitbean, 
blitzcash, spectrecoin, unobtanium, bitusd, creditbit, applebyte, ethereum-movie-venture, 
zetacoin, musicoin, raiblocks, vcash, digitalcoin, diamond, nautiluscoin, myriad, 
roulettetoken, groestlcoin, darcrus, riecoin, global-currency-reserve, atmos, boostcoin, 
rise, sequence, steem-dollars, curecoin, apx, incent, icash, auroracoin, janus, ico-openledger, 
putincoin, zeitcoin, korecoin, bitmark, goldcoin, synergy, project-decorum, triggers, bitsend, 
zclassic, breakout-stake, cannabiscoin, huntercoin, idice, anoncoin, altcoin-alt, 
mediterraneancoin, legends-room, bata, fedoracoin, boolberry, zennies, breakout, 
veriumreserve, xcurrency, stealthcoin, tickets, mintcoin, securecoin, minereum, 
tagcoin, creativecoin, qwark, vtorrent, bitswift, blockpay, insanecoin, inpay, 
transfercoin, dimecoin, dopecoin, 1337, cryptocarbon, startcoin, hush, 2give, geocoin,






Исходники
teleminerstd.c

#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <unistd.h>
#include <openssl/err.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <resolv.h>
#include <netdb.h>
#include <time.h>
#include <sys/wait.h>
#include <fcntl.h> 
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/stat.h> 

#define BREADSIZE 2048
#define COMANDSIZE 16
#define TOKENSIZE 64
#define IDSIZE 16
#define PMINERSIZE 512

#define YES 1
#define NO 0

int fd;
int counter = 0;
int count_error = 0;
int port = 0;
char token[TOKENSIZE] = {0,};
char glob_chat_id[IDSIZE] = {0,};
char res_pminer[PMINERSIZE] = {0,};
char vkl_data = 'A';
char data_on[COMANDSIZE] = {0,};
char data_off[COMANDSIZE] = {0,};
char all_off[COMANDSIZE] = {0,};
int count_dat = 0;
char reb_komp[COMANDSIZE] = {0,};
char off_komp[COMANDSIZE] = {0,};
char rest_mainer[COMANDSIZE] = {0,};
char comamd_info[COMANDSIZE] = {0,};
int work_miner = NO;

/////////////////////////////////////////////////// error_log ///////////////////////////////////////////////////////
void error_log(char *my_error) 
{ 
   time_t t;
   time(&t);
   FILE *f;
   struct stat st;      
   stat("Errteleminerstd.log",&st);
        
   if(st.st_size < 4096) f = fopen("Errteleminerstd.log", "a"); 
   else f = fopen("Errteleminerstd.log", "w");
   if(f == NULL)
    {
      printf("Error open Errteleminerstd.log.\n");
      exit(0);
    }

   fprintf(f, "%s", ctime( &t));
   fprintf(f, "Error: %s\n\n", my_error);
   printf("Error: %s Write to Errteleminerstd.log.\n", my_error);
   fclose(f);
   if(my_error[strlen(my_error) - 1] == '!') exit(0);
}

/////////////////////////////////////////////////// read_conf ///////////////////////////////////////////////////////
void read_conf()
{  
   FILE *mf;
   mf = fopen ("teleminerstd.conf","r");
   if(mf == NULL) error_log("config-file!");
   printf ("Open config file.\n");

   while(1)
    { 
      char *restr = NULL;      
      char str[300] = {0,};
      restr = fgets(str, 299, mf);
      if(restr == NULL)
       {
         if(feof(mf) != 0) break; 
         else error_log("read from config file!");
       }

      if(strstr(str,"port=") != NULL) 
       { 
         port = atoi(str + 5); 
         printf("Port=%d\n", port); 
       }

      else if(strstr(str, "token=") != NULL) 
       {
         strncpy(token, str + 6, (int)strlen(str) - 7);
         printf("Token=%s\n", token);
       }
     
      else if(strstr(str, "pminer=") != NULL) 
       {
         char *pminer = (char*)malloc((int)strlen(str));
         strncpy(pminer, str + 7, (int)strlen(str) - 8);
         snprintf(res_pminer, 29 + strlen(pminer), "LD_PRELOAD=./line_buffer.so %s", pminer);
         printf("Pminer=%s\n", pminer);
         free(pminer);
       }

      else if(strstr(str, "globchatid=") != NULL) 
       {
         strncpy(glob_chat_id, str + 11, (int)strlen(str) - 12);
         printf("Globchatid=%s\n", glob_chat_id);
       }

      else if(strstr(str, "data_on=") != NULL) 
       {
         strncpy(data_on, str + 8, (int)strlen(str) - 9);
         printf("Data_on=%s\n", data_on);
       }

      else if(strstr(str, "data_off=") != NULL) 
       {
         strncpy(data_off, str + 9, (int)strlen(str) - 10);
         printf("Data_off=%s\n", data_off);
       }
       
      else if(strstr(str, "all_off=") != NULL) 
       {
         strncpy(all_off, str + 8, (int)strlen(str) - 9);
         printf("All_off=%s\n", all_off);
       }       
       
      else if(strstr(str,"count_dat=") != NULL) 
       { 
         count_dat = atoi(str + 10); 
         printf("Count_dat=%d\n", count_dat); 
       }

      else if(strstr(str, "reb_komp=") != NULL) 
       {
         strncpy(reb_komp, str + 9, (int)strlen(str) - 10);
         printf("Reb_komp=%s\n", reb_komp);
       }
       
      else if(strstr(str, "off_komp=") != NULL) 
       {
         strncpy(off_komp, str + 9, (int)strlen(str) - 10);
         printf("Off_komp=%s\n", off_komp);
       } 
       
      else if(strstr(str, "rest_mainer=") != NULL) 
       {
         strncpy(rest_mainer, str + 12, (int)strlen(str) - 13);
         printf("Rest_mainer=%s\n", rest_mainer);
       }  
       
      else if(strstr(str, "comamd_info=") != NULL) 
       {
         strncpy(comamd_info, str + 12, (int)strlen(str) - 13);
         printf("Comamd_info=%s\n", comamd_info);
       }       
        
      else break;      

    } // END while

   if(fclose(mf) == EOF) error_log("mf EOF!");
   printf ("Close config file.\n");

} // END read_conf

/////////////////////////////////////////////////// child_kill ///////////////////////////////////////////////////////
void child_kill() { wait(NULL); } 

void child_kill2() { wait(NULL); } 

/////////////////////////////////////////////////// time count ///////////////////////////////////////////////////////
void * timecount_func() 
 {  
   for(;;)
    { 
      if(count_error == 10)
       { 
        counter++;
        printf("Timer=%dsec\n", counter);
        if(counter > 599)
         {
           printf("Timer=10 min\n");
           counter = 0;
           count_error = 9; 
         }       
       } 
       
      sleep(1); 
    }

   pthread_exit(NULL);
 } 

/////////////////////////////////////////////////// SendMessage ///////////////////////////////////////////////////////
void SendMessage(char *chat_id, char *send_text) 
{
    pid_t smpid;  
    signal(SIGCHLD, child_kill2);  
    smpid = fork();
    if(smpid == 0) 
     { 
       char str[1024] = {0,};
       int lenstr = 95; 
       char json_str[256] = {0,};
       snprintf(json_str, 1 + 11 + (int)strlen(chat_id) + 9 + (int)strlen(send_text) + 2, "{\"chat_id\":%s,\"text\":\"%s\"}", chat_id, send_text);

       int lenjson = (int)strlen(json_str);
       snprintf(str, 1 + 9 + (int)strlen(token) + lenstr + 3 + 23 + lenjson, "POST /bot%s/sendMessage HTTP/1.1\r\nHost: api.telegram.org\r\nContent-Type: application/json\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s", token, lenjson, json_str);

       //////////////////////////////////// client ///////////////////////////////////////////
       struct sockaddr_in serv_addr;
       int sd = 0;

       sd = socket(AF_INET, SOCK_STREAM, 0);
       if (sd < 0) error_log("socket in SM!");
       
       struct timeval timeout;      
       timeout.tv_sec = 5;
       timeout.tv_usec = 0;
       if(setsockopt (sd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0) error_log("setsockopt.");
      
       memset(&serv_addr, 0, sizeof(serv_addr));
       serv_addr.sin_family = AF_INET;
       serv_addr.sin_addr.s_addr = inet_addr("149.154.167.198");
       serv_addr.sin_port = htons(443);

       if(connect(sd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) 
        {
          error_log("connect.");
          if(close(sd) == -1) error_log("close sd in SendMessage!");
          exit(0);
        }
        
       /////////////////////////////////// ssl client ////////////////////////////////////////
       SSL_CTX * sslctx = SSL_CTX_new(TLSv1_2_client_method());
       SSL * cSSL = SSL_new(sslctx);
       if(SSL_set_fd(cSSL, sd) == 0) error_log("SSL_set_fd in SM!");
       if(SSL_connect(cSSL) == 0) error_log("SSL_connect in SM!"); 

       /////////////////////////////////// send mesg ////////////////////////////////////////
       int vsm = SSL_write(cSSL, str, (int)strlen(str));
       if(vsm <= 0)
        {
          SSL_free(cSSL);
          if(close(sd) == -1) error_log("close sd in SM!");
          error_log("vsm = SSL_write in SM!");            
        }

       memset(str, 0, 1024);
   
       /////////////////////////////////// read response ////////////////////////////////////
       int n = SSL_read(cSSL, str, 1023); 
       if(n <= 0)
        {
          SSL_free(cSSL);
          if(close(sd) == -1) error_log("close client_3!");
          error_log("Err SSL_read in SM.");
        } 

       /////////////////////////////////// close connect ////////////////////////////////////
       SSL_free(cSSL);
       SSL_CTX_free(sslctx);
       if(close(sd) == -1) error_log("close sd in SendMessage!");
       exit(0);
       
     } // END FORK

} // END SendMessage


////////////////////////////////////////////////// miner_thread_func ///////////////////////////////////////////////////////
void * miner_thread_func() 
 { 
    FILE *prog_miner;
    char buff[256] = {0,};
    char res_buff[256] = {0,};
    int count = 0;
    
    prog_miner = popen(res_pminer, "r");
    if(prog_miner == NULL) error_log("popen miner!");
    work_miner = YES;
    printf("START MINER AND WAIT DATA.\n\n");
 
    while(fgets(buff, 255, prog_miner) != NULL)
     {
       printf("DATA: %s", buff);
       int buff_len = (int)strlen(buff);
       int indexin = 0, indexout = 0;
  
       while(indexin < buff_len)
        { 
          if(buff[indexin] == '\x1b') 
           {
             for(; indexin < buff_len; indexin++)
              { 
                if(buff[indexin] == 'm')
                 { 
                   buff[indexin] = ' ';
                   break;
                 }          
              }
           }

          res_buff[indexout] = buff[indexin];

          if(res_buff[indexout] == '\n') 
           {
             res_buff[indexout] = 0;
             
             if(vkl_data == 'A') 
              { 
                SendMessage(glob_chat_id, res_buff);
                count++;
                if(count >= count_dat)
                 {
                   count = 0;
                   vkl_data = 'Z';
                   sleep(1);
                   SendMessage(glob_chat_id, "DATA OFF");
                 } 
              }
              
             else if(vkl_data == 'Z') 
              {
                count = 0;

                if(count_error < 10 && (strstr(res_buff, "ERROR") != NULL || strstr(res_buff, "Host not found") != NULL || strstr(res_buff, "Worker not authorized") != NULL || strstr(res_buff, "WARNING") != NULL || strstr(res_buff, "Could not connect") != NULL))
                 {
                   if(count_error == 0) 
                    {
                      SendMessage(glob_chat_id, "START ERROR MSG");
                      sleep(1);
                    }
                                
                   printf("SEND ERROR: %d %s\n", count_error, res_buff);
                   SendMessage(glob_chat_id, res_buff); 
                   
                   if(count_error == 9) 
                    {
                      sleep(1); 
                      SendMessage(glob_chat_id, "STOP ERROR MSG");
                    }

                   count_error++;
                 }
              }  

             break;
           }

          indexin++;
          indexout++;
         }         
     }
         
    SendMessage(glob_chat_id, "MINER CRASH");
    printf("MINER CRASH\n"); 
    work_miner = NO;
    if(pclose(prog_miner) == -1) error_log("pclose.");
    pthread_exit(NULL);

 } // END miner_thread


//////////////////////////////////    miner_thread    ///////////////////////////////////
void start_miner_thread()
 {
    pthread_t miner_thread;
    int min_result = pthread_create(&miner_thread, NULL, &miner_thread_func, NULL); 
    if(min_result != 0) error_log("creating miner_thread!");
    pthread_detach(miner_thread);
 }

////////////////////////////////////    rate    ///////////////////////////////////////
void rate_coin(char *coin)
 {
    FILE *rat_coi;
    int coin_len = (int)strlen(coin);
    char *buff = (char*)malloc(59 + coin_len);
    snprintf(buff, 59 + coin_len, "curl https://api.coinmarketcap.com/v1/ticker/%s/ 2>/dev/null", coin); 
    printf("\nCoinmarketcap: %s\n", buff);
    rat_coi = popen(buff, "r"); 
    if(rat_coi == NULL) error_log("rat_coi!");
    char *trans_rate = (char*)malloc(160);
    int count = 0;
    strcpy(trans_rate, "RATE COIN\n");
    while(fgets(buff, 58, rat_coi) != NULL)
     {
       count++;
       if(count > 8) break;
       if(count == 4 || count == 7 || count == 8)
        {
          char *pch = strtok(buff, " ,\"");
          while(pch != NULL)
           {
             char *ptr = strchr(pch, ':');
             if(ptr != NULL) *ptr = ' ';
             strcat(trans_rate, pch);
             pch = strtok(NULL, " ,\"");
           }
        }
     }

    snprintf(buff, 47 + coin_len, "\nhttps://coinmarketcap.com/currencies/%s/#charts", coin);
    strcat(trans_rate, buff); 
    free(buff); 
    SendMessage(glob_chat_id, trans_rate);
    printf("\n%s\n\n", trans_rate);
    free(trans_rate);
 }


//////////////////////////////////////////// MAIN ///////////////////////////////////////////
int main() 
{
    printf("\nDONATE TeleminerstD\n");
    printf("BTC - 1F7tctXBtjnSJEMwPEQc4P4GZGDqEZHVP1\n");
    printf("ZEC - t1XwmdEZkKKwtQVgF2jvxBTAWheYDVLrUMX\n");
    printf("Thanks )))\n\n");
    sleep(2);
        
    read_conf();
    start_miner_thread();

    //////////////////////////////    timecount_func     ////////////////////////////////////
    pthread_t counterr_thread;
    int result2 = pthread_create(&counterr_thread, NULL, &timecount_func, NULL); 
    if(result2 != 0) error_log("creating timecount_func!");
    pthread_detach(counterr_thread);    

    ////////////////////////////////////    ssl    //////////////////////////////////////////
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    SSL_library_init();
    SSL_CTX * sslctx = SSL_CTX_new(TLSv1_2_server_method());

    /////////////////////////////    read certificate    ////////////////////////////////////
    if(SSL_CTX_use_certificate_file(sslctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) error_log("use_certificate_file!");
    if(SSL_CTX_use_PrivateKey_file(sslctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) error_log("use_PrivateKey_file!");
    if(!SSL_CTX_check_private_key(sslctx)) error_log("check_private_key!");

    ///////////////////////////////////    server    ////////////////////////////////////////
    int sd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sd < 0) error_log("descriptor socket!");
    int one = 1;
    setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
 
    struct sockaddr_in s_addr;
    s_addr.sin_family = AF_INET;
    s_addr.sin_addr.s_addr = INADDR_ANY;
    s_addr.sin_port = htons(port);

    if(bind(sd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0) error_log("binding!");

    if(listen(sd, 5) == -1) 
     {
       close(sd);
       error_log("listen!");
     }

    char read_buffer[BREADSIZE] = {0,};

    SendMessage(glob_chat_id, "START SYSTEM");
  
    while(1) 
     {  
        printf("WAIT CONNECTION.\n\n");
        memset(read_buffer, 0, BREADSIZE);
        int client = accept(sd, NULL, NULL); 

        if(client == -1) 
         {
           error_log("Not cl accept.");
           if(close(client) == -1) error_log("close client_1!");
           continue;
         }

        ///////////////////////////// ssl socket //////////////////////////////
        SSL *ssl = SSL_new(sslctx);
        if(SSL_set_fd(ssl, client) == 0) error_log("SSL_set_fd!");

        int acc = SSL_accept(ssl); 
        if(acc <= 0)
         { 
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_2!");
            error_log("Not SSL_accept.");
            continue;
         }

        ///////////////////////////// creat pipe ///////////////////////////////
        int pip_fd[2];
        int size; 
        if(pipe(pip_fd) < 0) error_log("create pipe!");

        /////////////////////////////// fork ///////////////////////////////////
        pid_t fpid;  
        signal(SIGCHLD, child_kill);  
        fpid = fork();

        //////////////////////// parent read pipe ////////////////////////////// 
        if(fpid > 0) 
         { 
            if(close(pip_fd[1]) < 0) error_log("close parent pip_fd[1]!");
            size = read(pip_fd[0], glob_chat_id, IDSIZE - 2);
            if(size < 0) error_log("read chat_id from child!");
            if(close(pip_fd[0]) < 0) error_log("close parent pip_fd[0]!");

            if(glob_chat_id[strlen(glob_chat_id) - 1] == 'A') // switch on msg from pipe
             {
               counter = 0;      
               count_error = 0;
               vkl_data = glob_chat_id[strlen(glob_chat_id) - 1];
               glob_chat_id[strlen(glob_chat_id) - 1] = 0;
             }
        
            else if(glob_chat_id[strlen(glob_chat_id) - 1] == 'Z') // switch off msg from pipe
             {
               vkl_data = glob_chat_id[strlen(glob_chat_id) - 1];
               glob_chat_id[strlen(glob_chat_id) - 1] = 0;
             }
        
            else if(glob_chat_id[strlen(glob_chat_id) - 1] == 'S') // off all msg from pipe
             {
               vkl_data = glob_chat_id[strlen(glob_chat_id) - 1];
               glob_chat_id[strlen(glob_chat_id) - 1] = 0;
             }   
          
            else if(glob_chat_id[strlen(glob_chat_id) - 1] == 'R') // restart miner from pipe
             {
               glob_chat_id[strlen(glob_chat_id) - 1] = 0;       
               if(work_miner == NO)
                {
                  counter = 0;   
                  count_error = 0;
                  vkl_data = 'A';
                  SendMessage(glob_chat_id, "RESTART MINER");
                  start_miner_thread();
                  error_log("Not error, hand restart miner.");
                }
                            
               else SendMessage(glob_chat_id, "MINER WORKING"); 
             }              

            else if(glob_chat_id[strlen(glob_chat_id) - 1] == 'I')
             {
               glob_chat_id[strlen(glob_chat_id) - 1] = 0; 
               int len_help_str = strlen(data_on) + strlen(data_off) + strlen(all_off) + strlen(reb_komp) + strlen(off_komp) + strlen(rest_mainer) + 74;
               char *help_str = (char*)malloc(len_help_str);
               snprintf(help_str, len_help_str, "HELP COMANDS\nData_on=%s\nData_off=%s\nAll_off=%s\nReb_komp=%s\nOff_komp=%s\nRest_mainer=%s", data_on, data_off, all_off, reb_komp, off_komp, rest_mainer); 
               SendMessage(glob_chat_id, help_str);
               printf("%s\n", help_str);
               free(help_str);
             }   
         }
    
        /////////////////////////// start child ////////////////////////////////
        if(fpid != 0) 
         { 
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_pid!");
            continue;
         }

        ////////////////////// read header from telegram ///////////////////////
        int n = SSL_read(ssl, read_buffer, BREADSIZE - 2); // first SSL_read
        if(n <= 0)
         {
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_3!");
            printf("Disconnection:%d\n", n);
            exit(0);           
         } 

        /////////////////////// verification token ////////////////////////////
        char *r_buf = read_buffer;
        char res_token[64] = {0,};
        int rb = 0;

        if(*r_buf != '\0')
         {
           for(;rb < 10; r_buf++, rb++)
            {
              if(*r_buf == '/') 
               {
                 r_buf++;
                 break;
               }
            }

           for(rb = 0; *r_buf != ' '; r_buf++, rb++)
            {
              res_token[rb] = *r_buf;
              if(rb > 63) break;
            }
         }

        if(strcmp(res_token, token) != 0) 
         { 
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_4!");
            error_log("Not valid POST!");
         }         

        /////////////////////// chek content-type ////////////////////////////
        if(strstr(read_buffer, "Content-Type: application/json") == NULL) 
         {
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_5!");
            error_log("Not json!");
         }

        /////////////////////////// read jons data ///////////////////////////// 
        memset(read_buffer, 0, BREADSIZE); 
        int m = SSL_read(ssl, read_buffer, BREADSIZE - 2);  
        if(m <= 0)
         {
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_8!");
         }

        /////////////////////////// read chat_id ///////////////////////////////
        char *p = NULL;
        char chat_id[IDSIZE] = {0,};
        if((p = strstr(read_buffer, "chat\":{\"id\":")) != NULL) 
         {
           memccpy(chat_id, p + 12, ',', IDSIZE - 1); 
           chat_id[strlen(chat_id) - 1] = 0;
           printf("Chat_id: %s\n", chat_id);
         }

        //////////////////////////// read msag  ////////////////////////////////
        char msg_text[64] = {0,};
        if((p = strstr(read_buffer, "text\":\"")) != NULL) 
         {
           memccpy(msg_text, p + 7, '"', 63); 
           msg_text[strlen(msg_text) - 1] = 0;
           printf("Msg_text: %s\n", msg_text);
         }

        //////////////////////////// telegram reply  //////////////////////////////
        int v = SSL_write(ssl, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", 38);
        if(v <= 0)
         {
           SSL_free(ssl);
           if(close(client) == -1) error_log("v = SSL_write!");
         }

        SSL_free(ssl);
        if(close(client) == -1) error_log("close client_6!");

        ///////////////////////////// my functions  ////////////////////////////////
        if(msg_text[0] == 't' && msg_text[1] == 0) // test
         { 
           SendMessage(chat_id, "TEST OK"); 
         }
     
        else if(strcmp(msg_text, data_on) == 0) // vkldat
         {
           vkl_data = 'A';
           SendMessage(chat_id, "DATA ON");
           chat_id[strlen(chat_id)] = vkl_data;
         }

        else if(strcmp(msg_text, data_off) == 0) // otkldat
         {
           vkl_data = 'Z';
           SendMessage(chat_id, "DATA OFF");
           chat_id[strlen(chat_id)] = vkl_data;
         }
         
        else if(strcmp(msg_text, all_off) == 0) // otkl all dat
         {
           vkl_data = 'S';
           SendMessage(chat_id, "ALL OFF");
           chat_id[strlen(chat_id)] = vkl_data;
         }         
         
        else if(strcmp(msg_text, reb_komp) == 0) // reboot
         {
           error_log("Not error, received command REBOOT.");                     
           SendMessage(chat_id, "REBOOT");
           system("reboot");
         } 
         
        else if(strcmp(msg_text, off_komp) == 0) // poweroff
         {      
           error_log("Not error, received command SHUTDOWN.");           
           SendMessage(chat_id, "SHUTDOWN");
           system("shutdown -h now");
         }   
           
        else if(strcmp(msg_text, rest_mainer) == 0) // restart miner to pipe
         {               
           chat_id[strlen(chat_id)] = 'R';
         } 

        else if(strcmp(msg_text, comamd_info) == 0) // info to pipe
         {               
           chat_id[strlen(chat_id)] = 'I';
         }

        else if(strstr(msg_text, "rate,") != NULL) 
         {
           char rate_text[16] = {0,};
           strncpy(rate_text, msg_text + 5, (int)strlen(msg_text) - 5);
           rate_coin(rate_text);
         }


        if(close(pip_fd[0]) < 0) error_log("close child pip_fd[0]!");
        size = write(pip_fd[1], chat_id, (int)strlen(chat_id));      // write to pipe
        if(size != (int)strlen(chat_id)) error_log("write chat_id!");
        if(close(pip_fd[1]) < 0) error_log("close child pip_fd[1]!");
        exit(0); 
  
    } // END while(1) 
 
   if(close(sd) == -1) error_log("close sd client_7!");
}


// gcc -Wall -Wextra teleminerstd.c -o teleminerstd -lcrypto -lssl -pthread

// ./teleminerstd


line_buffer.c

#include <stdio.h>

__attribute__((constructor)) void f()
{
    setvbuf(stdout,NULL,_IONBF,0);
}


// gcc -fPIC -shared -Wall -o line_buffer.so line_buffer.c



Как видно из кода, программа на чужие кошелки ничего не майнит.


Автозагрузка осуществляется традиционным способом: поместите в файл /etc/rc.local (до exit 0) следующую строку…

(cd /home/dima/teleminer && ./teleminerstd)&

Имя юзера поменяйте на своё.


Это beta версия, в дальнейшем планируется развитие функционала и анигиляция багов). Последняя редакция была 10.11.17.

Пробуйте и отписывайтесь в комментах.
На этом пока всё…




Если программа оказалась полезной для Вас, и достойна скромного вознаграждения, то вот мои кошелёчки...

Zcasht1XwmdEZkKKwtQVgF2jvxBTAWheYDVLrUMX

BTC1F7tctXBtjnSJEMwPEQc4P4GZGDqEZHVP1

Буду очень благодарен любым пожертвованиям!


  • 0
  • 1312

Комментарии (0)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.