#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>           // close()
#include <string.h>           // strcpy, memset(), and memcpy()
#include <stdarg.h>
#include <errno.h>            // errno, perror()
#include <stdbool.h>
#include <pthread.h>
#include <semaphore.h>
#include <math.h>
#include <dirent.h> 
#include <fcntl.h>
#include <signal.h>
#include <getopt.h>
#include <termios.h>
#include <netdb.h>            // struct addrinfo
#include <sys/stat.h>
#include <sys/ioctl.h>        // macro ioctl is defined
#include <bits/ioctls.h>      // defines values for argument "request" of ioctl.
#include <sys/syscall.h>
#include <sys/types.h>        // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/select.h>
#include <sys/socket.h>       // needed for socket()
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <libgen.h>
#include <netinet/in.h>       // IPPROTO_ICMP, INET_ADDRSTRLEN
#include <netinet/ip.h>       // struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h>  // struct icmp, ICMP_ECHO
#include <arpa/inet.h>        // inet_pton() and inet_ntop()
#include <net/if.h>           // struct ifreq
#include <net/ethernet.h>
#include <linux/if_ether.h>   // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
#include <linux/if_packet.h>  // struct sockaddr_ll (see man 7 packet)
#include <linux/serial.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "mlogger.h"

#define UPDATE_SOCKET_SERVER "/tmp/app_run_server"
#define UPDATE_SOCKET_CLIENT "/tmp/app_run_client"

#define CS_LOGS_URL     "ftp://111.229.239.149:21/logs"
#define CS_USERNAME     "test"
#define CS_PASSWORD     "HCYhMPmnSS8M5id6"

void af_upgrade_app(const char* appname)
{
    struct sockaddr_un self;
    memset(&self, 0, sizeof(struct sockaddr_un));
    self.sun_family = AF_UNIX;
    strncpy(self.sun_path, UPDATE_SOCKET_CLIENT, sizeof(self.sun_path) - 1);
    if (access(UPDATE_SOCKET_CLIENT, F_OK) == 0) unlink(UPDATE_SOCKET_CLIENT);

    int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    int enable = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));

    if (bind(fd, (struct sockaddr*)&self, sizeof(struct sockaddr_un)) == 0)
    {
        struct sockaddr_un peer;
        memset(&peer, 0, sizeof(struct sockaddr_un));
        peer.sun_family = AF_UNIX;
        strncpy(peer.sun_path, UPDATE_SOCKET_SERVER, sizeof(peer.sun_path) - 1);
        sendto(fd, appname, strlen(appname), 0, (struct sockaddr*)&peer, sizeof(struct sockaddr_un));
        mlog_i("upgradeAPP: %s\n", appname);
        close(fd);
        if (access(UPDATE_SOCKET_CLIENT, F_OK) == 0) unlink(UPDATE_SOCKET_CLIENT);
    }
}

// curl命令中-O和-o选项的区别。
// -C offset 断点续传，指定到具体位置
// -C - 断点续传，自动从文件断点处
// -O 默认使用URL的最后一个部分作为文件名，
// -o 允许指定自定义的文件名，尤其适用于需要指定文件后缀的情况。
int af_download_app(const char* url, const char* username, const char* password)
{
    int i;
    uint8_t buff[512];
    if (url == NULL) url = CS_LOGS_URL;
    if (username == NULL) username = CS_USERNAME;
    if (password == NULL) password = CS_PASSWORD;
    
    sprintf(buff, "cd /home/root/app_run/bin/ \ncurl -C - -O %s -u %s:%s &\n", url, username, password);
    mlog_i("\n%s\n",buff);
    if (system(buff) == 0)
    {
        return 0;
    }
    return -1;
}

// curl -T /path/to/local/file ftp://111.229.239.149:21/logs/  -u test:HCYhMPmnSS8M5id6
int af_upload_log(const char* localfile, char* url, const char* username, const char* password)
{
    int i;
    uint8_t buff[512];
    if (localfile)
    {
        if (url == NULL) return -1;
        if (username == NULL) username = CS_USERNAME;
        if (password == NULL) password = CS_PASSWORD;
        sprintf(buff, "curl -T %s %s -u%s:%s\n", localfile, url, username, password);
        mlog_i("\n%s\n",buff);
        return system(buff);
    }
    return -1;
}

