static void DoHTTP( uint8_t timed ) { switch( curhttp->state ) { case HTTP_STATE_NONE: //do nothing if no state. break; case HTTP_STATE_DATA_XFER: if( TCPCanSend( curhttp->socket, 1024 ) ) //TCPDoneSend { if( curhttp->is_dynamic ) { HTTPCustomCallback( ); } else { HTTPHandleInternalCallback( ); } } break; case HTTP_WAIT_CLOSE: if( TCPDoneSend( curhttp->socket ) ) { if( curhttp->keep_alive ) { curhttp->state = HTTP_STATE_WAIT_METHOD; } else { HTTPClose( ); } } break; case HTTP_STATE_DATA_WEBSOCKET: if( TCPCanSend( curhttp->socket, 1024 ) ) //TCPDoneSend { WebSocketTickInternal(); } break; default: if( timed ) { if( curhttp->timeout++ > HTTP_SERVER_TIMEOUT ) { HTTPClose( ); } } } }
void HTTPCustomCallback( ) { uint16_t i, bytestoread; struct HTTPConnection * h = curhttp; if( h->isdone ) { HTTPClose( h->socket ); return; } if( h->isfirst ) { TCPs[h->socket].sendtype = ACKBIT | PSHBIT; StartTCPWrite( h->socket ); //TODO: Content Length? MIME-Type? PushStr( "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n" ); if( strncmp( h->pathbuffer, "/d/r1?", 6 ) == 0 ) { char outb[3] = {0, 0, 0}; char * bp = h->pathbuffer + 6; unsigned char address = 0; address += hex2val( *(bp++) )<<4; address += hex2val( *(bp++) ); unsigned char * cc = (unsigned char*)address; int8tohex( *cc, outb ); PushStr( outb ); } else if( strncmp( h->pathbuffer, "/d/w1?", 6 ) == 0 ) { char * bp = h->pathbuffer + 6; unsigned char address = 0; address += hex2val( *(bp++) )<<4; address += hex2val( *(bp++) ); unsigned char value = 0; value += hex2val( *(bp++) )<<4; value += hex2val( *(bp++) ); unsigned char * cc = (unsigned char*)address; *cc = value; } else if( strncmp( h->pathbuffer, "/d/r2?", 6 ) == 0 ) { char outb[3] = {0, 0, 0}; char * bp = h->pathbuffer + 6; unsigned char address = 0; address += hex2val( *(bp++) )<<4; address += hex2val( *(bp++) ); unsigned short * cc = (unsigned char*)address; unsigned short vo = *cc; int8tohex( vo>>8, outb ); PushStr( outb ); int8tohex( vo&0xff, outb ); PushStr( outb ); }
void TCPConnectionClosing( uint8_t conn ) { if( conn >= HTTP_CONNECTIONS ) { sendstr( "LOSC\n" ); RemovePlayer( conn - HTTP_CONNECTIONS - 1 ); } #ifndef NO_HTTP else { curhttp = &HTTPConnections[conn-1]; HTTPClose( ); } #endif }
void ICACHE_FLASH_ATTR HTTPGotData( ) { uint8 c; curhttp->timeout = 0; while( curlen-- ) { c = HTTPPOP; // sendhex2( h->state ); sendchr( ' ' ); switch( curhttp->state ) { case HTTP_STATE_WAIT_METHOD: if( c == ' ' ) { curhttp->state = HTTP_STATE_WAIT_PATH; curhttp->state_deets = 0; } break; case HTTP_STATE_WAIT_PATH: curhttp->pathbuffer[curhttp->state_deets++] = c; if( curhttp->state_deets == MAX_PATHLEN ) { curhttp->state_deets--; } if( c == ' ' ) { //Tricky: If we're a websocket, we need the whole header. curhttp->pathbuffer[curhttp->state_deets-1] = 0; curhttp->state_deets = 0; if( strncmp( (const char*)curhttp->pathbuffer, "/d/ws", 5 ) == 0 ) { curhttp->state = HTTP_STATE_DATA_WEBSOCKET; curhttp->state_deets = 0; } else { curhttp->state = HTTP_STATE_WAIT_PROTO; } } break; case HTTP_STATE_WAIT_PROTO: if( c == '\n' ) { curhttp->state = HTTP_STATE_WAIT_FLAG; } break; case HTTP_STATE_WAIT_FLAG: if( c == '\n' ) { curhttp->state = HTTP_STATE_DATA_XFER; InternalStartHTTP( ); } else if( c != '\r' ) { curhttp->state = HTTP_STATE_WAIT_INFLAG; } break; case HTTP_STATE_WAIT_INFLAG: if( c == '\n' ) { curhttp->state = HTTP_STATE_WAIT_FLAG; curhttp->state_deets = 0; } break; case HTTP_STATE_DATA_XFER: //Ignore any further data? curlen = 0; break; case HTTP_STATE_DATA_WEBSOCKET: WebSocketGotData( c ); break; case HTTP_WAIT_CLOSE: if( curhttp->keep_alive ) { curhttp->state = HTTP_STATE_WAIT_METHOD; } else { HTTPClose( ); } break; default: break; }; } }
void ICACHE_FLASH_ATTR HTTPHandleInternalCallback( ) { uint16_t i, bytestoread; if( curhttp->isdone ) { HTTPClose( ); return; } if( curhttp->is404 ) { START_PACK PushString("HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\nFile not found."); EndTCPWrite( curhttp->socket ); curhttp->isdone = 1; return; } if( curhttp->isfirst ) { char stto[10]; uint8_t slen = os_strlen( curhttp->pathbuffer ); const char * k; START_PACK; //TODO: Content Length? MIME-Type? PushString("HTTP/1.1 200 Ok\r\n"); if( curhttp->bytesleft < 0xfffffffe ) { PushString("Connection: "ISKEEPALIVE"\r\nContent-Length: "); Uint32To10Str( stto, curhttp->bytesleft ); PushBlob( stto, os_strlen( stto ) ); curhttp->keep_alive = 1; } else { PushString("Connection: close\r\n"); curhttp->keep_alive = 0; } PushString( "\r\nContent-Type: " ); //Content-Type? while( slen && ( curhttp->pathbuffer[--slen] != '.' ) ); k = &curhttp->pathbuffer[slen+1]; if( strcmp( k, "mp3" ) == 0 ) { PushString( "audio/mpeg3" ); } else if( strcmp( k, "gz" ) == 0 ) { PushString( "text/plain\r\nContent-Encoding: gzip\r\nCache-Control: public, max-age=3600" ); } else if( curhttp->bytesleft == 0xfffffffe ) { PushString( "text/plain" ); } else { PushString( "text/html" ); } PushString( "\r\n\r\n" ); EndTCPWrite( curhttp->socket ); curhttp->isfirst = 0; return; } START_PACK for( i = 0; i < 4 && curhttp->bytesleft; i++ ) { int bpt = curhttp->bytesleft; if( bpt > MFS_SECTOR ) bpt = MFS_SECTOR; curhttp->bytesleft = MFSReadSector( generic_ptr, &curhttp->data.filedescriptor ); generic_ptr += bpt; } EndTCPWrite( curhttp->socket ); if( !curhttp->bytesleft ) curhttp->isdone = 1; }
void TCPConnectionClosing( uint8_t conn ) { // sendstr( "Lostconn\n" ); HTTPClose( conn ); }
int main(int argc, char** argv) { if (argc < 2) return usage(argc, argv); parent = pthread_self(); sigset_t original, masking; sigemptyset(&original); sigemptyset(&masking); sigaddset(&masking, SIGUSR1); pthread_sigmask(SIG_SETMASK, &masking, &original); int wakeupThreads = 0; try { wakeupThreads = lexicalCast<int>(argv[argc-1]); if (wakeupThreads < 1) return usage(argc, argv); std::cout << "wakeup threads of " << wakeupThreads << std::endl; } catch (std::exception& e) { std::cerr << e.what() << std::endl; return usage(argc, argv); } void* handle = WWWInit(); std::vector<Item> items = loadItems(); resetItems(items); void* filterManagerContext = FilterManagerCreate(NULL); std::map<void*, void*> contextMap; // create threads. for (int count = 0; count != wakeupThreads; ++count) { std::vector<Item>::iterator itor = find_uncheck_item(items); if (itor == items.end()) break; itor->check_flg = true; void* thread = ThreadCreate(); void* httpContext = HTTPCreateContext(itor->url_check.c_str(), NULL, NULL, 20); contextMap[thread] = httpContext; std::cout << "thread: " << thread << " context: " << httpContext << std::endl; ThreadStart(thread, httpContext, handler); } try { std::vector<Item>::iterator itor; while ((itor = find_uncheck_item(items)) != items.end()) { itor->check_flg = true; int signalNum = 0; sigwait(&masking, &signalNum); if (signalNum == SIGUSR1) { // signal一回で複数の待ちハンドラを処理した方が良さそう ScopedLock<Mutex> lock(syncObject); assert (idleThreads.size() > 0); void* thread = idleThreads.back(); idleThreads.pop_back(); ThreadJoin(thread); void* httpContext = contextMap[thread]; assert(httpContext != NULL); contextMap[thread] = NULL; { char url[2048]; url[HTTPGetURL(httpContext, url, sizeof(url))] = 0; std::vector<Item>::iterator item_itor = find_item_from_url(items, url); if (item_itor == items.end()) throw std::runtime_error((std::string("unfind URL: ") + url).c_str()); char date[256]; date[HTTPGetLastModified(httpContext, date, sizeof(date))] = 0; item_itor->last_updated = date; item_itor->crc32 = HTTPGetFilteredCRC32(httpContext, filterManagerContext); item_itor->content_length = HTTPGetContentsLength(httpContext); HTTPClose(httpContext); } HTTPCreateContext(itor->url_check.c_str(), NULL, NULL, 20); contextMap[thread] = httpContext; std::cout << "thread: " << thread << " context: " << httpContext << std::endl; ThreadStart(thread, httpContext, handler); } } // 稼働中のスレッドがwakeupThreads個存在する for (int count = 0; count != wakeupThreads; ++count) { int signalNum = 0; // signal一回で複数の待ちハンドラを処理した方が良さそう sigwait(&masking, &signalNum); ScopedLock<Mutex> lock(syncObject); ThreadClose(idleThreads.back()); idleThreads.pop_back(); } } catch (std::exception& e) { std::cerr << "raise exception: " << e.what() << std::endl; } catch (...) { std::cerr << "unknown exception raised." << std::endl; } saveItems(items); FilterManagerTerminate(filterManagerContext); WWWTerminate(handle); pthread_sigmask(SIG_SETMASK, &original, NULL); return 0; }