#include #include //memcmp 要 include 的 header #include #include //getpid() #include #include #include #include //sockaddr_in #include //socket() #define PORT 80 // Client 所要連線的 port #define MAXDATASIZE 500 //最大可收的 bytes 大小 char ip[50]; char port[50]; char user[50]; char password[50]; char folder[50]; char command[500]; char serial[50]; int checkT = 0, checkR = 0; //0為complete; -1回傳開檔失敗; -2回傳 傳檔/收檔失敗 的錯誤 Message int errorCountR = 0, errorCountT = 0; void readConfig() //用來存取 ip, port, password 等等變數的 function { FILE *fp; fp = fopen("service.cfg", "r"); //開檔,讀取service.cfg的檔案 if(fp == NULL) printf("open failure\n"); else { while(1) { fgets(command, 500, fp); //從fp中一次讀取一行指令(500字元)到common中 if(feof(fp)) //如讀到底則 Break { break; } else { char check[500]; sscanf(command, "%s %*s", check); //從command中讀取前面的字元存到 check 中,後面的字元省略 if(memcmp(check, "IP", 2) == 0) //如 (check == "IP") 則從 command 中讀取後面的字元存到 ip 變數中,前面的字元省略 { sscanf(command, "%*s %s", ip); } else if(memcmp(check, "PORT", 4) == 0) { sscanf(command, "%*s %s", port); } else if(memcmp(check, "PASSWORD", 8) == 0) { sscanf(command, "%*s %s", password); } else if(memcmp(check, "USER", 4) == 0) { sscanf(command, "%*s %s", user); } else if(memcmp(check, "FOLDER", 6) == 0) { sscanf(command, "%*s %s", folder); } } } fclose(fp); } } /*void readSerialNo() //用來讀取序號用的 function { FILE *fp2; fp2 = fopen("/proc/cpuinfo", "r"); if(fp2 == NULL) { printf("open failure\n"); } else { while(1) { fgets(command, 500, fp2); if(feof(fp2)) { break; } else { char check[500]; sscanf(command, "%s %*[]", check); if(memcmp(check, "Serial", 6) == 0) { sscanf(command, "%*[^:] %*s %s", serial); //從command中,前面到:為止都省略掉,再省略一個空格,讀取最後一個字元存到serial //printf("%s\n", serial); sprintf(serial, "%s", serial); //把serial存成指定格式(%s) //printf("%d\n", strlen(serial)); //測試serial有幾個字元 } } } fclose(fp2); //記得關檔 } }*/ void FileRevOk() //查看是否成功下載檔案,如成功跳出"file recv successfully" { //如失敗跳出 "file not recv" char buf[500]; FILE *pp; printf("Befor receive, 以上正常\n"); if((pp = popen(command, "r")) == NULL) { printf("popen() error!\n"); checkR = -1; return; //回傳 not found } else { while(fgets(buf, sizeof(buf), pp)) { //printf("%s", buf); if(memcmp(buf, "file recv ok", 12) == 0) { printf("file recv successfully\n"); pclose(pp); checkR = 0; return; } } pclose(pp); printf("file not recv\n"); checkR = -2; return; } } void FileTransferOk() { char buf[500]; FILE *pp; puts("Befor transfer, 以上正常\n"); if((pp = popen(command, "r")) == NULL) { printf("popen() error!\n"); checkT = -1; return; } else { while(fgets(buf, sizeof(buf), pp)) { if(memcmp(buf, "Transfer OK.", 12) == 0) { printf("file transfer successfully\n"); pclose(pp); checkT = 0; return; } } pclose(pp); printf("file not transfer\n"); checkT = -2; return; } } //////////////////////////////////////////////////////////////////////////////// // // // tcpConnect // // // //////////////////////////////////////////////////////////////////////////////// int tcpConnect(int return_code, char msg[50]) { int sockfd; //socket的描述 int i; int numbytes; int service_code; char buf[MAXDATASIZE]; struct hostent *host; struct sockaddr_in info; struct timeval tv; sprintf(buf, "GET /index.php?inst=%s&&code=%d&&msg=%s HTTP/1.1\r\n", serial, return_code, msg); i = strlen(buf); if(return_code == 400) { //printf("Failure, Error message : %s\n", message); sprintf(&buf[i], "Host: %s\r\nConnection: Failure\r\n\r\n\r\n\0\0\0\0\0\0\0", ip); } else if(return_code == 777) { //printf("complete\n"); sprintf(&buf[i], "Host: %s\r\nConnection: Complete\r\n\r\n\r\n\0\0\0\0\0\0\0", ip); } else if(return_code == 666) { //printf("under processing\n"); sprintf(&buf[i], "Host: %s\r\nConnection: Keep-Alive\r\n\r\n\r\n\0\0\0\0\0\0\0", ip); } else { puts("your return_code is wrong.\n"); } sockfd = socket(AF_INET, SOCK_STREAM, 0); //socket的描述浮 if(sockfd == -1) { perror("socket"); exit(1); } bzero(&info, sizeof(info)); //初始化,將struct涵蓋的bits設為0 info.sin_family = AF_INET; //使用IPv4協定的地址 info.sin_addr.s_addr = inet_addr(ip); //IP address, inet_addr()可將字串IP變成 binary's IP //info.sin_addr.s_addr = inet_addr("10.0.0.49");//先指向自己的 IP 練習, 可以把防火牆打開測試connected的timeout info.sin_port = htons(PORT); //埠號,Host TO Network Short integer的縮寫,它將本機端的字節序(endian)轉換成了網路端的字節序 //printf("test %x\n", info.sin_addr.s_addr); //socket的連線 //沒有timeout版本的connect if((connect(sockfd, (struct sockaddr *)&info, sizeof(info))) == -1) { perror("connect"); exit(1); } printf("connect successfully\n"); //沒有timeout版本的connect //有timeout 版本的connect /*int res = connect(sockfd, (struct sockaddr *)&info, sizeof(info)); if(res < 0) { if(errno == EINPROGRESS) //connect 還在進行中 { perror("EINPROGRESS in connect"); fd_set myset; do { tv.tv_sec = 10; tv.tv_usec = 0; FD_ZERO(&myset); FD_SET(sockfd, &myset); res = select(sockfd+1, NULL, &myset, NULL, &tv); if(res < 0 && errno != EINTR) { perror("connect error"); exit(1); } else if(res >0) { socklen_t len; int valopt; len = sizeof(int); if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len) < 0) //getsockopt can determine if the socket is connected (=0, connected) { perror("Error in getsockopt()"); exit(1); } if(valopt) { perror("Error in delay"); exit(1); } break; } else { perror("Timeout"); exit(1); } }while(1); } else { perror("connect error"); exit(1); } }//有timeout版的connect */ //傳送資料(send a message on a socket),如正確 send 會回傳實際送出的 Byte 數 if((send(sockfd, buf, sizeof(buf), 0)) == -1) { perror("send"); exit(1); } //printf("send:\n%s\n", buf); printf("After the send function \n\n"); //接收資料,如正確 recv 會回傳實際讀到並寫入到 buffer 的 Byte 數 numbytes = recv(sockfd, buf, sizeof(buf), 0); //printf("numbytes = %d\n", numbytes); if(numbytes == -1) { perror("recv"); exit(1); } close(sockfd); buf[numbytes] = '\0'; printf("Received in pid = %d, text = %s \n", getpid(), buf); return 0; } int updateFirmware() { int sockfd; //socket的描述 int i; int numbytes; int service_code; char buf[12] = {1,2,0,0,0,6,1,6,0,0x70,1,0x81}; struct hostent *host; struct sockaddr_in info; i = strlen(buf); sockfd = socket(AF_INET, SOCK_STREAM, 0); //socket的描述浮 if(sockfd == -1) { perror("socket"); exit(1); } bzero(&info, sizeof(info)); //初始化,將struct涵蓋的bits設為0 info.sin_family = AF_INET; //使用IPv4協定的地址 //info.sin_addr.s_addr = inet_addr(ip); //IP address, inet_addr()可將字串IP變成 binary's IP info.sin_addr.s_addr = inet_addr("127.0.0.1");//先指向自己的 IP 練習, 可以把防火牆打開測試connected的timeout info.sin_port = htons(502); //埠號,Host TO Network Short integer的縮寫,它將本機端的字節序(endian)轉換成了網路端的字節序 //socket的連線 //沒有timeout版本的connect if((connect(sockfd, (struct sockaddr *)&info, sizeof(info))) == -1) { perror("connect"); exit(1); } //傳送資料(send a message on a socket),如正確 send 會回傳實際送出的 Byte 數 if((send(sockfd, buf, sizeof(buf), 0)) == -1) { perror("send"); exit(1); } printf("After the send function \n\n"); //接收資料,如正確 recv 會回傳實際讀到並寫入到 buffer 的 Byte 數 numbytes = recv(sockfd, buf, sizeof(buf), 0); if(numbytes == -1) { perror("recv"); exit(1); } close(sockfd); buf[numbytes] = '\0'; return 0; } ///////////////////// main /////////////////////////////////////////// int main(int argc, char *argv[]) { int return_code; int version; int date; return_code = atoi(argv[4]); version = atoi(argv[6]); date = atoi(argv[8]); sprintf(serial, "%s", argv[9]); readConfig(); //呼叫存取ip,password等等變數的function if(return_code == 0) //如return_code為0,則輸出0且結束 printf("0\n"); //do nothing else if(return_code == 400) puts("工作失敗\n"); else if(return_code == 666) puts("上一個程式還在執行中\n"); else if(return_code == 777) puts("已完成\n"); else if(return_code == 10|| return_code == 110 || return_code == 20 || return_code == 120 || return_code == 1 || return_code == 101 || return_code == 200 || return_code == 300) { tcpConnect(666, ""); //呼叫tcp function會回處理中(參數666) errorCountPlus: //如errorCountR or errorCountT <3會用goto回到這裡再執行一次 switch(return_code) { case 10: //如return_code為 010 則上傳 vAlert8.cfg sprintf(command, "./ftpUpload.exe %s %s %s %s %s vAlert8.cfg STOR", ip, port, user, password, folder); //printf("test command %s\n", command); //sprintf 為,把這些格式的值寫到command中 system(command); //叫 system 去執行command(自己設的變數) FileTransferOk(); break; case 110: //如return_code為 110 則下載 vAlert8.cfg sprintf(command, "./ftpClient.exe %s %s %s %s vAlert8.cfg reset\n", ip, port, user, password); //printf("%s\n", command); system(command); FileRevOk(); break; case 20: //如return_code為 020 則上傳 vAlert8Common.cfg sprintf(command, "./ftpUpload.exe %s %s %s %s %s vAlert8Common.cfg STOR", ip, port, user, password, folder); //printf("%s\n", command); system(command); FileTransferOk(); break; case 120: //如return_code為 120 則下載 vAlert8Common.cfg sprintf(command, "./ftpClient.exe %s %s %s %s vAlert8Common.cfg reset", ip, port, user, password); //printf("%s\n",command); system(command); FileRevOk(); break; case 1: //如return_code為 001 則上傳清單上的檔案,需先下載再上傳檔案清單 sprintf(command, "./ftpClient.exe %s %s %s %s uploadFileList_%s reset", ip, port, user, password, serial); system(command); //先下載檔案 FileRevOk(); FILE *fp3; fp3 = fopen("uploadFileList.txt","r"); if(fp3 == NULL) { printf("open failure\n"); } else //再上傳檔案清單 { char temp[500]; fgets(temp, 500, fp3); sprintf(command,"./ftpUpload.exe %s %s %s %s %s/%s uploadFileList_%s STOR", ip, port, user, password, folder, temp, serial); //printf("%s\n", command); system(command); FileTransferOk(); } fclose(fp3); break; case 101: //如return_code為 101 則單純下載檔案清單 sprintf(command, "./ftpClients.exe %s %s %s %s uploadFileList_%s reset", ip, port, user, password, serial); //printf("%s\n", command); system(command); FileRevOk(); break; case 200: puts("更新韌體\n"); updateFirmware(); break; case 300: //如return_code為 300 則先下載 run_serial.sh,並執行排程 sprintf(command, "./ftpClient.exe %s %s %s %s run_%s.sh reset", ip, port, user, password, serial); //printf("%s\n", command); system(command); FileRevOk(); sprintf(command, "sudo chmod +x run_%s.sh", serial);//改成可執行檔 //printf("first %s\n", command); system(command); sprintf(command, "sudo ./run_%s.sh", serial); //執行排程 //printf("second %s\n", command); system(command); break; }//end switch }//end else if else { puts("wrong code\n"); } if(checkR == 0 && checkT == 0) //FileRevOk && FileTransferOk 的結果都收到OK回傳777 { tcpConnect(777, ""); } else //Received 沒收到三次會回傳400 { if(checkR != 0 && errorCountR < 3) { errorCountR++; printf("Received fail %d time\n", errorCountR); checkR = 0; goto errorCountPlus; } else if(checkR == -1) tcpConnect(400, "popen()_error"); else if(checkR == -2) tcpConnect(400, "file_not_recv"); if(checkT != 0 && errorCountT < 3) //Transfer 沒收到三次會回傳400 { errorCountT++; printf("Transfer fail %d time\n", errorCountT); checkT = 0; goto errorCountPlus; } else if(checkT == -1) tcpConnect(400, "popen()_error"); else if(checkT == -2) tcpConnect(400, "file_not_transfer"); } return 0; }