static OSStatus onReceivedData(struct _HTTPHeader_t * inHeader, uint32_t inPos, uint8_t * inData, size_t inLen, void * inUserContext ) { OSStatus err = kUnknownErr; const char * value; size_t valueSize; configContext_t *context = (configContext_t *)inUserContext; err = HTTPGetHeaderField( inHeader->buf, inHeader->len, "Content-Type", NULL, NULL, &value, &valueSize, NULL ); if(err == kNoErr && strnicmpx( value, valueSize, kMIMEType_MXCHIP_OTA ) == 0){ config_log("OTA data %d, %d to: %x", inPos, inLen, context->flashStorageAddress); #ifdef MICO_FLASH_FOR_UPDATE if(inPos == 0){ context->flashStorageAddress = UPDATE_START_ADDRESS; mico_rtos_lock_mutex(&Context->flashContentInRam_mutex); //We are write the Flash content, no other write is possiable context->isFlashLocked = true; err = MicoFlashInitialize( MICO_FLASH_FOR_UPDATE ); require_noerr(err, flashErrExit); err = MicoFlashErase(MICO_FLASH_FOR_UPDATE, UPDATE_START_ADDRESS, UPDATE_END_ADDRESS); require_noerr(err, flashErrExit); err = MicoFlashWrite(MICO_FLASH_FOR_UPDATE, &context->flashStorageAddress, (uint8_t *)inData, inLen); require_noerr(err, flashErrExit); }else{ err = MicoFlashWrite(MICO_FLASH_FOR_UPDATE, &context->flashStorageAddress, (uint8_t *)inData, inLen); require_noerr(err, flashErrExit); } #else config_log("OTA storage is not exist"); return kUnsupportedErr; #endif } else if(inHeader->chunkedData == true){ config_log("ChunkedData: %d, %d:", inPos, inLen); for(uint32_t i = 0; i<inLen; i++) printf("%c", inData[i]); printf("\r\n"); } else{ return kUnsupportedErr; } if(err!=kNoErr) config_log("onReceivedData"); return err; #ifdef MICO_FLASH_FOR_UPDATE flashErrExit: MicoFlashFinalize(MICO_FLASH_FOR_UPDATE); mico_rtos_unlock_mutex(&Context->flashContentInRam_mutex); return err; #endif }
void localConfiglistener_thread(void *inContext) { config_log_trace(); OSStatus err = kUnknownErr; int j; Context = inContext; struct sockaddr_t addr; int sockaddr_t_size; fd_set readfds; char ip_address[16]; int localConfiglistener_fd = -1; /*Establish a TCP server fd that accept the tcp clients connections*/ localConfiglistener_fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); require_action(IsValidSocket( localConfiglistener_fd ), exit, err = kNoResourcesErr ); addr.s_ip = INADDR_ANY; addr.s_port = CONFIG_SERVICE_PORT; err = bind(localConfiglistener_fd, &addr, sizeof(addr)); require_noerr( err, exit ); err = listen(localConfiglistener_fd, 0); require_noerr( err, exit ); config_log("Config Server established at port: %d, fd: %d", CONFIG_SERVICE_PORT, localConfiglistener_fd); while(1){ FD_ZERO(&readfds); FD_SET(localConfiglistener_fd, &readfds); select(1, &readfds, NULL, NULL, NULL); /*Check tcp connection requests */ if(FD_ISSET(localConfiglistener_fd, &readfds)){ sockaddr_t_size = sizeof(struct sockaddr_t); j = accept(localConfiglistener_fd, &addr, &sockaddr_t_size); if (j > 0) { inet_ntoa(ip_address, addr.s_ip ); config_log("Config Client %s:%d connected, fd: %d", ip_address, addr.s_port, j); err = mico_rtos_create_thread(NULL, MICO_APPLICATION_PRIORITY, "Config Clients", localConfig_thread, STACK_SIZE_LOCAL_CONFIG_CLIENT_THREAD, &j); } } } exit: config_log("Exit: Local controller exit with err = %d", err); mico_rtos_delete_thread(NULL); return; }
static void _easylinkConnectWiFi( mico_Context_t * const inContext) { config_log_trace(); network_InitTypeDef_adv_st wNetConfig; memset(&wNetConfig, 0x0, sizeof(network_InitTypeDef_adv_st)); mico_rtos_lock_mutex(&inContext->flashContentInRam_mutex); strncpy((char*)wNetConfig.ap_info.ssid, inContext->flashContentInRam.micoSystemConfig.ssid, maxSsidLen); wNetConfig.ap_info.security = SECURITY_TYPE_AUTO; memcpy(wNetConfig.key, inContext->flashContentInRam.micoSystemConfig.user_key, maxKeyLen); wNetConfig.key_len = inContext->flashContentInRam.micoSystemConfig.user_keyLength; wNetConfig.dhcpMode = inContext->flashContentInRam.micoSystemConfig.dhcpEnable; strncpy((char*)wNetConfig.local_ip_addr, inContext->flashContentInRam.micoSystemConfig.localIp, maxIpLen); strncpy((char*)wNetConfig.net_mask, inContext->flashContentInRam.micoSystemConfig.netMask, maxIpLen); strncpy((char*)wNetConfig.gateway_ip_addr, inContext->flashContentInRam.micoSystemConfig.gateWay, maxIpLen); strncpy((char*)wNetConfig.dnsServer_ip_addr, inContext->flashContentInRam.micoSystemConfig.dnsServer, maxIpLen); wNetConfig.wifi_retry_interval = 100; mico_rtos_unlock_mutex(&inContext->flashContentInRam_mutex); micoWlanStartAdv(&wNetConfig); config_log("connect to %s.....", wNetConfig.ap_info.ssid); }
int main(int argc, char* argv[]) { config_fout = stdout; config_ferr = stderr; if (argc == 1) { help(argv[0]); return -1; } int mode_specified = 0, do_init = 0; char* configpath = NULL; FILE* configfile; int c; while (1) { static struct option long_options[] = { {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"log", required_argument, NULL, 'l'}, {"init", 0, NULL, 'i'}, {"update", 0, NULL, 'u'}, {0,0,0,0} }; int option_index = 0; c = getopt_long(argc, argv, "hvl:iu", long_options, &option_index); if (c == -1) {//unknown arg (doesnt match -x/--x format) if (optind >= argc) { //at end of successful parse break; } //getopt refuses to continue, so handle infile manually: int i = optind; for (; i < argc; ++i) { configpath = argv[i]; //debug("%d %d %s", argc, i, arg); configfile = fopen(configpath,"r"); if (configfile == NULL) { config_error("Unable to open config file %s: %s", configpath, strerror(errno)); mini_help(argv[0]); return -1; } } break; } switch (c) { case 'h': help(argv[0]); return -1; case 'v': config_debug_enabled = 1; break; case 'l': { FILE* logfile = fopen(optarg, "a"); if (logfile == NULL) { config_error("Unable to open log file %s: %s", optarg, strerror(errno)); return -1; } config_fout = logfile; config_ferr = logfile; } break; case 'i': mode_specified = 1; do_init = 1; break; case 'u': mode_specified = 1; do_init = 0; break; default: mini_help(argv[0]); return -1; } } if (!mode_specified) { config_error("-i/-u mode argument required."); mini_help(argv[0]); } int error = -1; if (configpath == NULL) { configpath = "<stdin>"; configfile = stdin; } config_log("Parsing %s",configpath); //Get and parse bb_frames (both STRINGs and TEXTs) from config: struct bb_frame* startframe = NULL; if (parsefile(&startframe,configfile) < 0) { fclose(configfile); config_error("Error encountered when parsing config file. "); mini_help(argv[0]); goto end_noclose; } fclose(configfile); if (startframe == NULL) { config_error("Empty config file, nothing to do. "); mini_help(argv[0]); goto end_noclose; } usbsign_handle* devh = NULL; if (hardware_init(&devh) < 0) { config_error("USB init failed: Exiting. "); mini_help(argv[0]); goto end_noclose; } char* packet = NULL; int pktsize; config_log("Writing to sign"); //send sequence header before we start sending packets if (!hardware_seqstart(devh)) { //try resetting device once config_error("Initial write failed, attempting reset."); if (!hardware_reset(&devh)) { config_error("Reset failed: Exiting."); goto end; } if (!hardware_seqstart(devh)) { config_error("Initial write retry failed, giving up."); goto end; } config_log("Reset successful, continuing"); } if (do_init) { //this packet allocates sign memory for messages: if ((pktsize = packet_buildmemconf(&packet,startframe)) < 0) { goto end; } if (hardware_sendpkt(devh,packet,pktsize) != pktsize) { goto end; } free(packet); packet = NULL; } //now on to the real messages: struct bb_frame* curframe = startframe; while (curframe != NULL) { config_debug("result: data=%s",curframe->data); if (curframe->frame_type == STRING_FRAME_TYPE) { //data will be updated often, store in a STRING file pktsize = packet_buildstring(&packet,curframe->filename, curframe->data); } else if (curframe->frame_type == TEXT_FRAME_TYPE) { if (!do_init) { curframe = curframe->next; config_debug(" ^-- SKIPPING: init-only packet"); continue; } //data wont be updated often, use a TEXT file pktsize = packet_buildtext(&packet,curframe->filename, curframe->mode,curframe->mode_special, curframe->data); } else { config_error("Internal error: Unknown frame type %d",curframe->frame_type); goto end; } if (hardware_sendpkt(devh,packet,pktsize) != pktsize) { goto end; } free(packet); packet = NULL; curframe = curframe->next; } if (do_init) { //set display order for the messages: pktsize = packet_buildrunseq(&packet,startframe); if (hardware_sendpkt(devh,packet,pktsize) != pktsize) { goto end; } free(packet); packet = NULL; } //finish it off with a sequence footer if (!hardware_seqend(devh)) { goto end; } error = 0; end: hardware_close(devh); end_noclose: if (startframe != NULL) { packet_delete(startframe); free(startframe); } return error; }
OSStatus _LocalConfigRespondInComingMessage(int fd, HTTPHeader_t* inHeader, mico_Context_t * const inContext) { OSStatus err = kUnknownErr; const char * json_str; uint8_t *httpResponse = NULL; size_t httpResponseLen = 0; json_object* report = NULL; config_log_trace(); if(HTTPHeaderMatchURL( inHeader, kCONFIGURLRead ) == kNoErr){ report = ConfigCreateReportJsonMessage( inContext ); require( report, exit ); json_str = json_object_to_json_string(report); require_action( json_str, exit, err = kNoMemoryErr ); config_log("Send config object=%s", json_str); err = CreateSimpleHTTPMessageNoCopy( kMIMEType_JSON, strlen(json_str), &httpResponse, &httpResponseLen ); require_noerr( err, exit ); require( httpResponse, exit ); err = SocketSend( fd, httpResponse, httpResponseLen ); require_noerr( err, exit ); err = SocketSend( fd, (uint8_t *)json_str, strlen(json_str) ); require_noerr( err, exit ); config_log("Current configuration sent"); goto exit; } else if(HTTPHeaderMatchURL( inHeader, kCONFIGURLWrite ) == kNoErr){ if(inHeader->contentLength > 0){ config_log("Recv new configuration, apply and reset"); err = ConfigIncommingJsonMessage( inHeader->extraDataPtr, inContext); require_noerr( err, exit ); inContext->flashContentInRam.micoSystemConfig.configured = allConfigured; MICOUpdateConfiguration(inContext); err = CreateSimpleHTTPOKMessage( &httpResponse, &httpResponseLen ); require_noerr( err, exit ); require( httpResponse, exit ); err = SocketSend( fd, httpResponse, httpResponseLen ); SocketClose(&fd); inContext->micoStatus.sys_state = eState_Software_Reset; if(inContext->micoStatus.sys_state_change_sem != NULL ); mico_rtos_set_semaphore(&inContext->micoStatus.sys_state_change_sem); mico_thread_sleep(MICO_WAIT_FOREVER); } goto exit; } else if(HTTPHeaderMatchURL( inHeader, kCONFIGURLWriteByUAP ) == kNoErr){ if(inHeader->contentLength > 0){ config_log("Recv new configuration from uAP, apply and connect to AP"); err = ConfigIncommingJsonMessageUAP( inHeader->extraDataPtr, inContext); require_noerr( err, exit ); MICOUpdateConfiguration(inContext); err = CreateSimpleHTTPOKMessage( &httpResponse, &httpResponseLen ); require_noerr( err, exit ); require( httpResponse, exit ); err = SocketSend( fd, httpResponse, httpResponseLen ); require_noerr( err, exit ); sleep(1); micoWlanSuspendSoftAP(); _easylinkConnectWiFi( inContext ); err = kConnectionErr; //Return an err to close socket and exit the current thread } goto exit; } #ifdef MICO_FLASH_FOR_UPDATE else if(HTTPHeaderMatchURL( inHeader, kCONFIGURLOTA ) == kNoErr){ if(inHeader->contentLength > 0){ config_log("Receive OTA data!"); memset(&inContext->flashContentInRam.bootTable, 0, sizeof(boot_table_t)); inContext->flashContentInRam.bootTable.length = inHeader->contentLength; inContext->flashContentInRam.bootTable.start_address = UPDATE_START_ADDRESS; inContext->flashContentInRam.bootTable.type = 'A'; inContext->flashContentInRam.bootTable.upgrade_type = 'U'; if(inContext->flashContentInRam.micoSystemConfig.configured != allConfigured) inContext->flashContentInRam.micoSystemConfig.easyLinkByPass = EASYLINK_SOFT_AP_BYPASS; MICOUpdateConfiguration(inContext); SocketClose(&fd); inContext->micoStatus.sys_state = eState_Software_Reset; if(inContext->micoStatus.sys_state_change_sem != NULL ); mico_rtos_set_semaphore(&inContext->micoStatus.sys_state_change_sem); mico_thread_sleep(MICO_WAIT_FOREVER); } goto exit; } #endif else{ return kNotFoundErr; }; exit: if(inHeader->persistent == false) //Return an err to close socket and exit the current thread err = kConnectionErr; if(httpResponse) free(httpResponse); if(report) json_object_put(report); return err; }
void localConfig_thread(void *inFd) { OSStatus err; int clientFd = *(int *)inFd; int clientFdIsSet; fd_set readfds; struct timeval_t t; HTTPHeader_t *httpHeader = NULL; configContext_t httpContext = {0, false}; config_log_trace(); httpHeader = HTTPHeaderCreateWithCallback(onReceivedData, onClearHTTPHeader, &httpContext); require_action( httpHeader, exit, err = kNoMemoryErr ); HTTPHeaderClear( httpHeader ); t.tv_sec = 60; t.tv_usec = 0; config_log("Free memory %d bytes", MicoGetMemoryInfo()->free_memory) ; while(1){ FD_ZERO(&readfds); FD_SET(clientFd, &readfds); clientFdIsSet = 0; if(httpHeader->len == 0){ require(select(1, &readfds, NULL, NULL, &t) >= 0, exit); clientFdIsSet = FD_ISSET(clientFd, &readfds); } if(clientFdIsSet||httpHeader->len){ err = SocketReadHTTPHeader( clientFd, httpHeader ); switch ( err ) { case kNoErr: // Read the rest of the HTTP body if necessary //do{ err = SocketReadHTTPBody( clientFd, httpHeader ); if(httpHeader->dataEndedbyClose == true){ err = _LocalConfigRespondInComingMessage( clientFd, httpHeader, Context ); require_noerr(err, exit); err = kConnectionErr; goto exit; }else{ require_noerr(err, exit); err = _LocalConfigRespondInComingMessage( clientFd, httpHeader, Context ); require_noerr(err, exit); } // if(httpHeader->contentLength == 0) // break; //} while( httpHeader->chunkedData == true || httpHeader->dataEndedbyClose == true); // Call the HTTPServer owner back with the acquired HTTP header //err = _LocalConfigRespondInComingMessage( clientFd, httpHeader, Context ); // //Exit if connection is closed //require_noerr(err, exit); // Reuse HTTPHeader HTTPHeaderClear( httpHeader ); break; case EWOULDBLOCK: // NO-OP, keep reading break; case kNoSpaceErr: config_log("ERROR: Cannot fit HTTPHeader."); goto exit; case kConnectionErr: // NOTE: kConnectionErr from SocketReadHTTPHeader means it's closed config_log("ERROR: Connection closed."); goto exit; default: config_log("ERROR: HTTP Header parse internal error: %d", err); goto exit; } } } exit: config_log("Exit: Client exit with err = %d", err); SocketClose(&clientFd); if(httpHeader) { HTTPHeaderClear( httpHeader ); free(httpHeader); } mico_rtos_delete_thread(NULL); return; }