[recovery mode] Telegrambot на си + Arduino

geek.png
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  

#define BREADSIZE 2048
#define AREADSIZE 128

int fd;
int port = 0;
char token[64] = {0,};
char mkpatch[32] = {0,};
unsigned long int baudrate = 0;
char bRead[AREADSIZE] = {0,};


void error_log(char *my_error) 
{ 
   time_t t;
   time(&t);
   FILE *f;
   f = fopen("ErrTelebot.log", "a"); 
   if(f == NULL)
    {
      printf("Error open ErrTelebot.log.\n");
      exit(0);
    }

   fprintf(f, "%s", ctime( &t));
   fprintf(f, "Error: %s\n\n", my_error);
   printf("Error: %s Write to ErrTelebot.log.\n", my_error);
   fclose(f);
   exit(0);
}


void read_conf()
{  
   FILE *mf;
   char str[64] = {0,};
   char *restr;
   mf = fopen ("Telebot.conf","r");
   if(mf == NULL) error_log("mf.");
   printf ("Open config file.\n");
   while(1)
    {
      restr = fgets(str, sizeof(str), mf);
      if(restr == NULL)
       {
         if(feof(mf) != 0) break; 
         else error_log("read from config file.");
       }

      if(strstr(str,"port=") != NULL) { port = atoi(strstr(str, "port=") + 5); printf("Port:%d_END\n", port); }
      char *p;
      if((p = strstr(str,"token=")) != NULL) 
       {
         int index = p - str;
         int i = 0;
         int ot = index + 6;
         for(; i <= 62; i++)
          {
            token[i] = str[ot];
            ot++;
            if(token[i] == '\n') 
             {
               token[i] = '\0';
               printf("Token:%s_END\n", token);
               break;
             }
          }
       }

      char *mkp;
      if((mkp = strstr(str,"mkpatch=")) != NULL) 
       {
         int index = mkp - str;
         int i = 0;
         int ot = index + 8;
         for(; i <= 14; i++)
          {
            mkpatch[i] = str[ot];
            ot++;
            if(mkpatch[i] == '\n') 
             {
               mkpatch[i] = '\0';
               printf("Mkpatch:%s_END\n", mkpatch);
               break;
             }
          }
       }

      char *sp;
      if((sp = strstr(str,"baudrate=")) != NULL) 
       {
         char mkspeed[8] = {0,};
         int index = sp - str;
         int i = 0;
         int ot = index + 9;
         for(; i <= 7; i++)
          {
            mkspeed[i] = str[ot];
            ot++;
            if(mkspeed[i] == '\n') 
             {
               baudrate = strtoul(mkspeed, NULL, 0);
               printf("Baudrate:%lu_END\n", baudrate);
               break;
             }
          }
       }

    } // END while

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


void child_kill() { printf("Child_kill.\n"); wait(NULL); } 

void SendMessage(char *chat_id, char *send_text) 
{
    char host[] = "api.telegram.org"; 
    char str[1024] = {0,};
    int lenstr = (int)strlen("/sendMessage HTTP/1.1\r\nHost: api.telegram.org\r\nContent-Type: application/json\r\nContent-Length: ");
    char json_str[128] = {0,};
    snprintf(json_str, 1 + 11 + (int)strlen(chat_id) + 9 + (int)strlen(send_text) + 2, "%s%s%s%s%s", "{\"chat_id\":", chat_id, ",\"text\":\"", send_text, "\"}");

//printf("Json_str:%s_END\n", json_str);
    int lenjson = (int)strlen(json_str);
    snprintf(str, 1 + 9 + (int)strlen(token) + lenstr + 3 + (int)strlen("\r\nConnection: close\r\n\r\n") + lenjson, "%s%s%s%d%s%s", "POST /bot", token, "/sendMessage HTTP/1.1\r\nHost: api.telegram.org\r\nContent-Type: application/json\r\nContent-Length: ", lenjson, "\r\nConnection: close\r\n\r\n", json_str);
    
//printf("\nSEND_POST:%d\n%s_END\n", (int)strlen(str), str);
    struct hostent *server; 
    struct sockaddr_in serv_addr;
    int sd = 0;
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0) error_log("socket in SM.");
    server = gethostbyname(host); 
    if (server == NULL) error_log("host in SM."); 
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(443);
    memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); 

    if(connect(sd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) error_log("connect.");
    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."); 
    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.");            
     }

printf("\nSendMessage.\n");
    memset(str, 0, 1024); 
    int n = SSL_read(cSSL, str, 1022); 
    if(n <= 0)
     {
       SSL_free(cSSL);
       if(close(sd) == -1) error_log("close client_3.");
       printf("Err SSL_read in SM.\n");
     } 

//printf("\nReport_SM:%d\n%s\n", n, str);
    SSL_free(cSSL);
    SSL_CTX_free(sslctx);
    if(close(sd) == -1) error_log("close sd in SendMessage.");
}


void ardu_read_func(char *chat_id) 
 { 
   int i = 0;
   //int err_count1 = 0;
   int bytes = 0;
   memset(bRead, 0, AREADSIZE * sizeof(char));
   //counterr = 0;

   if((bytes = read(fd, bRead, AREADSIZE - 1)) == -1) error_log("Read_from_Arduino.");
   for(i = 0; i <= bytes; i++)
    {
      if(bRead[i] == '\n')
       {
         bRead[i] = 0; 
         break;
       }
    } 

   tcflush(fd, TCIFLUSH); 
printf("SM_from_Ardu:%s_%s\n\n", chat_id, bRead);
   SendMessage(chat_id, bRead);
  
 } // END ardu_read_func


/////////////////////////////////////////// open_port /////////////////////////////////////////////////
void open_port()  
 {   
   fd = open(mkpatch, O_RDWR | O_NOCTTY); 
   if(fd == -1) error_log("open /dev/ttyXXX.");
   else  
     {  
       struct termios options;  
       tcgetattr(fd, &options);   

       switch(baudrate)
       {
        case 4800:       
          cfsetispeed(&options, B4800); 
          cfsetospeed(&options, B4800); 
        break;

        case 9600:       
          cfsetispeed(&options, B9600); 
          cfsetospeed(&options, B9600); 
        break;

        case 19200:       
          cfsetispeed(&options, B19200); 
          cfsetospeed(&options, B19200); 
        break;

        case 38400:       
          cfsetispeed(&options, B38400); 
          cfsetospeed(&options, B38400); 
        break;

        case 57600:       
          cfsetispeed(&options, B57600); 
          cfsetospeed(&options, B57600); 
        break;

        case 115200:       
          cfsetispeed(&options, B115200); 
          cfsetospeed(&options, B115200); 
        break;

        default: 
          error_log("baudrate_port.");
        break;
       }

       options.c_cflag |= (CLOCAL | CREAD); 
       options.c_iflag = IGNCR;
       options.c_cflag &= ~PARENB;  
       options.c_cflag &= ~CSTOPB;  
       options.c_cflag &= ~CSIZE;  
       options.c_cflag |= CS8;  
       options.c_cc[VMIN] = 1;  
       options.c_cc[VTIME] = 1;  
       options.c_lflag = ICANON;  
       options.c_oflag = 0;  
       options.c_oflag &= ~OPOST; 
       tcflush(fd, TCIFLUSH);
       tcsetattr(fd, TCSANOW, &options);  
     }  
 }


int main() 
{
    read_conf();

    open_port(); 
    sleep(2);
    tcflush(fd, TCIFLUSH);

    ////////////////////////////////////    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,};
    int client = 0;
  
    while(1) 
     {  
        printf("Wait connection.\n");
        memset(read_buffer, 0, BREADSIZE);

        client = accept(sd, NULL, NULL); 

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

//printf("OK_1.\n");
        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.");
            printf("Not SSL_accept.\n");
            continue;
         }

//printf("OK2_acc:%d\n", acc);
 
        /////////////////////// FORK ///////////////////////////
        pid_t pid;  
        signal(SIGCHLD, child_kill);  
        pid = fork();
        
        if(pid != 0) 
         { 
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_pid.");
            continue;
         }

        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);           
         } 

//printf("First SSL_read:%d %s\n", n, read_buffer);
//printf("OK_3.\n");

        if(strstr(read_buffer, token) == NULL) 
         { 
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_4.");
            printf("Not valid POST.\n");
            exit(0);
         }

//printf("OK_4.\n");
        if(strstr(read_buffer, "Content-Type: application/json") == NULL) 
         {
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_5.");
            printf("Not json.\n");
            exit(0);
         }

//printf("OK_5.\n");

        int len = atoi(strstr(read_buffer, "Content-Length: ") + strlen("Content-Length: "));

        memset(read_buffer, 0, BREADSIZE); 
        int m = SSL_read(ssl, read_buffer, len);  // second SSL_read
        if(m <= 0)
         {
            SSL_free(ssl);
            if(close(client) == -1) error_log("close client_8.");
            error_log("m = SSL_read.");            
         }

//printf("\nSecond SSL_read:%d %s\n", m, read_buffer);

        char *p;
        //memset(chat_id, 0, 16);
        char chat_id[16] = {0,};
        if((p = strstr(read_buffer, "chat\":{\"id\":")) != NULL) 
         {
           int index = p - read_buffer;
           int i = 0;
           int ot = index + 12;
           for(; i <= 14; i++)
            {
              chat_id[i] = read_buffer[ot];
              ot++;
              if(chat_id[i] == ',') 
               {
                 chat_id[i] = 0;
                 printf("\nchat_id:%s_END\n", chat_id);
                 break;
               }
            }
         }


        char *q;
        char msg_text[64] = {0,};
        //long int comanda = 0;
        if((q = strstr(read_buffer, "text\":\"")) != NULL) 
         {
           int index = q - read_buffer;
           int i = 0;
           int ot = index + 7;
           for(; i <= 62; i++)
            {
              msg_text[i] = read_buffer[ot];
              ot++;
              if(msg_text[i] == '"') 
               {
                 msg_text[i] = 0;
                 printf("Text:%s_END\n", msg_text);
                 //comanda = strtol(msg_text, NULL, 0);
                 //printf("Comanda:%ld_END\n", comanda);
                 break;
               }
            }
         }

        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.");


        if(msg_text[0] == 't' && msg_text[1] == 0)
         { 
           SendMessage(chat_id, "TEST"); 
         }
      
        else
         {
           char to_Ardu[128] = {0,};
           snprintf(to_Ardu, strlen(msg_text) + strlen(mkpatch) + 11, "echo '%s' > %s", msg_text, mkpatch);
           printf("\nto_Ardu:%s_END\n", to_Ardu);
           system(to_Ardu);
           ardu_read_func(chat_id);
         }

        exit(0); 
  
    } // END while(1) 
 
   if(close(sd) == -1) error_log("close sd client_7.");
}


// gcc -Wall -Wextra telebot.c -o telebot -lcrypto -lssl


© Geektimes