#include "httpserver.h" #include "lwip/tcp.h" #include "fsdata.c" #include "main.h" #include "flash_if.h" #include "common_config.h" #include "settings_api.h" #include "crc.h" #include "gpio_io.h" #include "systick.h" #include #include "tinystdio.h" #define FILENAME_MAX_LEN 30 /** * @brief Общая структура настроек */ extern SETTINGS_t sSettings; extern uint8_t fDoneReset; extern uint8_t fErrorReset; char debugMsg[40]; static vu32 DataFlag=0; static vu32 size =0; static __IO uint32_t FlashWriteAddress; static u32 TotalReceived=0; static char LeftBytesTab[4]; static u8 LeftBytes=0; static __IO u8 resetpage=0; static uint32_t ContentLengthOffset =0,BrowserFlag=0; static __IO uint32_t TotalData=0, checklogin=0; static bool fEraseFlash = true; static bool hw_validated = false; static uint32_t ContentOffset = 0; static uint8_t reqCounter = 0; static uint8_t reqTimer = 0; struct http_state { char *file; u32_t left; }; htmlpageState htmlpage; static const char http_crnl_2[4] = /* "\r\n--" */ {0xd, 0xa,0x2d,0x2d}; static const char octet_stream[14] = /* "octet-stream" */ {0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,0x0d, }; static const char Content_Length[17] = /* Content Length */ {0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67,0x74, 0x68, 0x3a, 0x20, }; static uint32_t Parse_Content_Length(char *data, uint32_t len); char* Parce_Boundary(const char* data, uint32_t len, char* dst, uint8_t dstlen); static void IAP_HTTP_writedata(char* data, uint32_t len); /* file must be allocated by caller and will be filled in by the function. */ static int fs_open(char *name, struct fs_file *file); uint16_t printLen = 0; char printBuf[1500]; uint32_t oldAdd = USER_FLASH_FIRST_PAGE_ADDRESS; uint32_t deltaAdd = 0; /** * @brief callback function for handling connection errors * @param arg: pointer to an argument to be passed to callback function * @param err: LwIP error code * @retval none */ static void conn_err(void *arg, err_t err) { struct http_state *hs; hs = arg; mem_free(hs); } /** * @brief closes tcp connection * @param pcb: pointer to a tcp_pcb struct * @param hs: pointer to a http_state struct * @retval */ static void close_conn(struct tcp_pcb *pcb, struct http_state *hs) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); mem_free(hs); tcp_close(pcb); reqCounter++; } /** * @brief sends data found in member "file" of a http_state struct * @param pcb: pointer to a tcp_pcb struct * @param hs: pointer to a http_state struct * @retval none */ static void send_data(struct tcp_pcb *pcb, struct http_state *hs) { err_t err; u16_t len; /* We cannot send more data than space available in the send buffer */ if (tcp_sndbuf(pcb) < hs->left) { len = tcp_sndbuf(pcb); } else { len = hs->left; } err = tcp_write(pcb, hs->file, len, 0); if (err == ERR_OK) { hs->file += len; hs->left -= len; } } /** * @brief tcp poll callback function * @param arg: pointer to an argument to be passed to callback function * @param pcb: pointer on tcp_pcb structure * @retval err_t */ static err_t http_poll(void *arg, struct tcp_pcb *pcb) { if (arg == NULL) { tcp_close(pcb); } else { send_data(pcb, (struct http_state *)arg); } return ERR_OK; } /** * @brief callback function called after a successfull TCP data packet transmission * @param arg: pointer to an argument to be passed to callback function * @param pcb: pointer on tcp_pcb structure * @param len * @retval err : LwIP error code */ static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len) { struct http_state *hs; hs = arg; if (hs->left > 0){ // printf("send"); send_data(pcb, hs); } else { printf("close"); close_conn(pcb, hs); if (htmlpage == UploadDonePage) fDoneReset = 1; else if (htmlpage == UploadErrorPage) fErrorReset = 1; } return ERR_OK; } /** * @brief callback function for handling TCP HTTP traffic * @param arg: pointer to an argument structure to be passed to callback function * @param pcb: pointer to a tcp_pcb structure * @param p: pointer to a packet buffer * @param err: LwIP error code * @retval err */ /* goback.cgi - возврат в основную прошивку */ /* upload.cgi - загрузка новой прошивки */ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { int32_t i, len=0; uint32_t DataOffset, FilenameOffset; char *data, *ptr, filename[13]; struct fs_file file = {0, 0}; struct http_state *hs; hs = arg; if (err == ERR_OK && p != NULL) { /* Inform TCP that we have taken the data */ tcp_recved(pcb, p->tot_len); if (hs->file == NULL) { data = p->payload; len = p->tot_len; printLen = p->tot_len; memcpy(printBuf, p->payload , printLen); //printf(printBuf); /* process HTTP GET requests */ if (strncmp(data, "GET /", 5) == 0) {/* if ((strncmp(data, "GET /resetmcu.cgi", 17) ==0)&&(htmlpage == UploadDonePage)) { htmlpage = ResetDonePage; fs_open("/reset.html", &file); hs->file = file.data; hs->left = file.len; pbuf_free(p); send_data(pcb, hs); resetpage = 1; tcp_sent(pcb, http_sent); }*/ if (strncmp(data, "GET /upload.css", 15) == 0) { fs_open("/upload.css", &file); hs->file = file.data; hs->left = file.len; pbuf_free(p); send_data(pcb, hs); tcp_sent(pcb, http_sent); } else if (strncmp(data, "GET /upload.js", 14) == 0) { fs_open("/upload.js", &file); hs->file = file.data; hs->left = file.len; pbuf_free(p); send_data(pcb, hs); tcp_sent(pcb, http_sent); } /* Возврат в основную прошивку. Сбрасываем флаг loadmode, сохраняем настройки и перезагружаемся */ else if (strncmp(data, "GET /goback.cgi", 15)==0) { RTC_WriteBackupRegister(RTC_BKP_DR1, 0); /* sSettings.bootParams.loadMode = 0; SETTINGS_Save();*/ Delay_ms(1010); NVIC_SystemReset(); } else if (strncmp(data, "GET /favicon.ico", 16) == 0) { fs_open("/favicon.ico", &file); hs->file = file.data; hs->left = file.len; send_data(pcb, hs); tcp_sent(pcb, http_sent); } else { /*send the login page (which is the index page) */ htmlpage = LoginPage; fs_open("/index.html", &file); hs->file = file.data; hs->left = file.len; pbuf_free(p); send_data(pcb, hs); tcp_sent(pcb, http_sent); } } #if 1 /* process POST request for file upload and incoming data packets after POST request*/ else if ((strncmp(data, "POST /upload.cgi",16) == 0) || (DataFlag >= 1)) { /*if (fEraseFlash) { FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS); fEraseFlash = false; }*/ static char boundary[70]; static char boundary_buf[70]; static char *pbound = NULL; DataOffset = 0; /* POST Packet received */ if (DataFlag == 0) { BrowserFlag = 0; TotalReceived = 0; /* parse packet for Content-length field */ size = Parse_Content_Length(data, p->tot_len); pbound = Parce_Boundary(data, p->tot_len, boundary, sizeof(boundary)); //printf("boundary: %s\r\n", boundary); /* parse packet for the octet-stream field */ for (i = 0; i < len; i++) { /* TODO remove if tested */ // if (strncmp ((char*)(data+i), octet_stream, 13)==0) // { // DataOffset = i + 16; // break; // } if (pbound != NULL) { if (strncmp ((char*)(data+i), boundary, strlen(boundary))==0) { ContentOffset = i; /* parse packet for "\r\n\r\n" field */ for (int32_t j= 0; j < len; j++) { if (strncmp ((char*)(data+i+j), "\r\n\r\n", 4)==0) { DataOffset = i + j + 4; break; } } } } } /* case of MSIE8 : we do not receive data in the POST packet*/ if (DataOffset == 0) { DataFlag++; BrowserFlag = 1; pbuf_free(p); return ERR_OK; } /* case of Mozilla Firefox v3.6 : we receive data in the POST packet*/ else { TotalReceived = len - ContentOffset; } } if (((DataFlag ==1)&&(BrowserFlag==1)) || ((DataFlag ==0)&&(BrowserFlag==0))) { if ((DataFlag ==0)&&(BrowserFlag==0)) { DataFlag++; } else if ((DataFlag ==1)&&(BrowserFlag==1)) { /* parse packet for the octet-stream field */ for (i = 0; i < len; i++) { if (pbound != NULL) { if (strncmp ((char*)(data+i), boundary, strlen(boundary))==0) { /* parse packet for "\r\n\r\n" field */ for (int32_t j= 0; j < len; j++) { if (strncmp ((char*)(data+i+j), "\r\n\r\n", 4)==0) { DataOffset = i + j + 4; break; } } } } } TotalReceived += len; DataFlag++; } /* parse packet for the filename field */ FilenameOffset = 0; for (i = 0; i < len; i++) { if (strncmp ((char*)(data+i), "filename=", 9)==0) { FilenameOffset = i+10; break; } } i = 0; if (FilenameOffset) { while((*(data+FilenameOffset + i)!=0x22 )&&(ifile = file.data; hs->left = file.len; pbuf_free(p); /* send index.html page */ send_data(pcb, hs); /* Tell TCP that we wish be to informed of data that has been successfully sent by a call to the http_sent() function. */ tcp_sent(pcb, http_sent); DataFlag=0; return ERR_OK; } PRINT_USART("\n\r IAP using HTTP \n\r"); sprintf(debugMsg, "File: %s\n\r",filename); PRINT_USART(debugMsg); PRINT_USART("State: Erasing...\n\r"); TotalData =0 ; /* init flash */ /// FLASH_If_Init(); /* erase user flash area */ //FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS); // / FlashWriteAddress = USER_FLASH_FIRST_PAGE_ADDRESS; /*indicate start of flash programming */ PRINT_USART("\n\rState: Programming..\n\r"); } /* DataFlag >1 => the packet is data only */ else { TotalReceived +=len; } ptr = (char*)(data + DataOffset); len-= DataOffset; /* update Total data received counter */ TotalData +=len; /* check if last data packet */ if (TotalReceived == size) { /* if last packet need to remove the http boundary tag */ /* parse packet for "\r\n--" starting from end of data */ /* i = 4; while (strncmp ((char*)(data+ p->tot_len -i),http_crnl_2 , 4)) { i++; } len -= i; TotalData -= i; */ /* write data in Flash */ if(hw_validated){ if (len) IAP_HTTP_writedata(ptr,len); DataFlag=0; htmlpage = UploadDonePage; PRINT_USART("Tot bytes Received:\n\r"); sprintf(debugMsg, "%d bytes \n\r",TotalData); PRINT_USART(debugMsg); PRINT_USART("State: Prog Finished \n\r"); } /* Проверяем CRC */ if (hw_validated && CRC_Read() == CRC_Calcucate()) { fs_open("/success.html", &file); hs->file = file.data; hs->left = file.len; send_data(pcb, hs); tcp_sent(pcb, http_sent); htmlpage = UploadDonePage; } else { if(hw_validated) FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS); fEraseFlash = false; fs_open("/error.html", &file); hs->file = file.data; hs->left = file.len; send_data(pcb, hs); tcp_sent(pcb, http_sent); htmlpage = UploadErrorPage; } /* sSettings.bootParams.loadMode = 0; SETTINGS_Save(); IO_KeyBlockOn(); Delay_ms(1010); NVIC_SystemReset(); */ } /* not last data packet */ else { if ((TotalData >= HW_REV_OFFSET + HW_REV_LEN) && (!hw_validated)) { char rev[HW_REV_LEN]; strncpy(rev, HW_REV, HW_REV_LEN); if (strcmp((char *)(ptr + HW_REV_OFFSET), rev) != 0) { // DataFlag = 0; pbuf_free(p); /* fs_open("/error.html", &file); hs->file = file.data; hs->left = file.len;*/ /* send_data(pcb, hs); tcp_sent(pcb, http_sent);*/ // printf("start"); // htmlpage = UploadErrorPage; // fErrorReset = 1; // pbuf_free(p); //close_conn(pcb, hs); return ERR_OK; } else { hw_validated = true; // Erase flash if (fEraseFlash) { FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS); fEraseFlash = false; } // Init flash FLASH_If_Init(); FlashWriteAddress = USER_FLASH_FIRST_PAGE_ADDRESS; } } /* write data in flash */ if(len) IAP_HTTP_writedata(ptr,len); } pbuf_free(p); } else { /* Bad HTTP requests */ PRINT_USART("Bad HTTP request\n\r"); pbuf_free(p); close_conn(pcb, hs); } #endif } else { pbuf_free(p); close_conn(pcb,hs); } } if (err == ERR_OK && p == NULL) { /* received empty frame */ PRINT_USART("Received empty frame\n\r"); close_conn(pcb, hs); } return ERR_OK; } /** * @brief callback function on TCP connection setup ( on port 80) * @param arg: pointer to an argument structure to be passed to callback function * @param pcb: pointer to a tcp_pcb structure * ¶m err: Lwip stack error code * @retval err */ static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct http_state *hs; /* Allocate memory for the structure that holds the state of the connection */ hs = mem_malloc(sizeof(struct http_state)); if (hs == NULL) { return ERR_MEM; } /* Initialize the structure. */ hs->file = NULL; hs->left = 0; /* Tell TCP that this is the structure we wish to be passed for our callbacks. */ tcp_arg(pcb, hs); /* Tell TCP that we wish to be informed of incoming data by a call to the http_recv() function. */ tcp_recv(pcb, http_recv); tcp_err(pcb, conn_err); tcp_poll(pcb, http_poll, 10); return ERR_OK; } /** * @brief intialize HTTP webserver * @param none * @retval none */ void IAP_httpd_init(void) { struct tcp_pcb *pcb; /*create new pcb*/ pcb = tcp_new(); /* bind HTTP traffic to pcb */ tcp_bind(pcb, IP_ADDR_ANY, 80); /* start listening on port 80 */ pcb = tcp_listen(pcb); /* define callback function for TCP connection setup */ tcp_accept(pcb, http_accept); } /** * @brief Opens a file defined in fsdata.c ROM filesystem * @param name : pointer to a file name * @param file : pointer to a fs_file structure * @retval 1 if success, 0 if fail */ static int fs_open(char *name, struct fs_file *file) { struct fsdata_file_noconst *f; for (f = (struct fsdata_file_noconst *)FS_ROOT; f != NULL; f = (struct fsdata_file_noconst *)f->next) { if (!strcmp(name, f->name)) { file->data = f->data; file->len = f->len; return 1; } } return 0; } /** * @brief Extract the Content_Length data from HTML data * @param data : pointer on receive packet buffer * @param len : buffer length * @retval size : Content_length in numeric format */ static uint32_t Parse_Content_Length(char *data, uint32_t len) { uint32_t i=0,size=0, S=1; int32_t j=0; char sizestring[6], *ptr; ContentLengthOffset =0; /* find Content-Length data in packet buffer */ for (i=0;i0) { /* transform string data into numeric format */ for(j=i-1;j>=0;j--) { size += (sizestring[j]-0x30)*S; S=S*10; } } } return size; } char* Parce_Boundary(const char* data, uint32_t len, char* dst, uint8_t dstlen) { char *ptr = NULL; char *boundary = NULL; uint8_t i = 0; for (uint32_t j = 0; j < len; j++) { if (strncmp ((char*)(data + j), "boundary=", 9) == 0) { boundary = (char*)data + j + 9; break; } } if (!boundary) return NULL; *dst++ = '-'; *dst++ = '-'; ptr = boundary; while ((*ptr != 0x0d) && (i < dstlen - 4)) { *dst++ = *ptr++; i++; } //*dst++ = '-'; //*dst++ = '-'; *dst = '\0'; if (i > 0) return boundary; else return NULL; } /** * @brief writes received data in flash * @param ptr: data pointer * @param len: data length * @retval none */ void IAP_HTTP_writedata(char * ptr, uint32_t len) { uint32_t count, i=0, j=0; /* check if any left bytes from previous packet transfer*/ /* if it is the case do a concat with new data to create a 32-bit word */ if (LeftBytes) { while(LeftBytes<=3) { if(len>(j+1)) { LeftBytesTab[LeftBytes++] = *(ptr+j); } else { LeftBytesTab[LeftBytes++] = 0xFF; } j++; } FLASH_If_Write(&FlashWriteAddress, (u32*)(LeftBytesTab),1); LeftBytes =0; /* update data pointer */ ptr = (char*)(ptr+j); len = len -j; } /* write received bytes into flash */ count = len/4; /* check if remaining bytes < 4 */ i= len%4; if (i>0) { if (TotalReceived != size) { /* store bytes in LeftBytesTab */ LeftBytes=0; for(;i>0;i--) LeftBytesTab[LeftBytes++] = *(char*)(ptr+ len-i); } else count++; } FLASH_If_Write(&FlashWriteAddress, (u32*)ptr ,count); } uint32_t ReturnFlashWriteAddress(void) { return FlashWriteAddress; } /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/