📄 miniserver2.cpp
字号:
// refill empty buffer if ( !bufferHasData() ) { status = refillBuffer(); if ( status <= 0 ) return status; if ( !bufferHasData() ) return 0; dataLeft = buflen; } else { dataLeft = buflen - offset; } if ( bufferLen < dataLeft ) { copyLen = bufferLen; } else { copyLen = dataLeft; } memcpy( buf, &data[offset], copyLen ); offset += copyLen; return copyLen;}ssize_t NetReader1::refillBuffer(){ ssize_t numRead; // test version //numRead = DoRead( sockfd, data, maxbufsize ); numRead = read( sockfd, data, maxbufsize ); if ( numRead >= 0 ) { buflen = numRead; } else { buflen = 0; } offset = 0; return numRead;}static void WriteNetData( const char* s, int sockfd ){ write( sockfd, s, strlen(s) ); } // determines type of UPNP command from request line, lnstatic HTTP_COMMAND_TYPE GetCommandType( const xstring& ln ){ // commands GET, POST, M-POST, SUBSCRIBE, UNSUBSCRIBE, NOTIFY xstring line = ln; int i; char c; char * getStr = "GET"; char * postStr = "POST"; char * mpostStr = "M-POST"; char * subscribeStr = "SUBSCRIBE"; char * unsubscribeStr = "UNSUBSCRIBE"; char * notifyStr = "NOTIFY"; char * pattern; HTTP_COMMAND_TYPE retCode=CMD_HTTP_UNKNOWN; try { line.toUppercase(); c = line[0]; switch (c) { case 'G': pattern = getStr; retCode = CMD_HTTP_GET; break; case 'P': pattern = postStr; retCode = CMD_SOAP_POST; break; case 'M': pattern = mpostStr; retCode = CMD_SOAP_MPOST; break; case 'S': pattern = subscribeStr; retCode = CMD_GENA_SUBSCRIBE; break; case 'U': pattern = unsubscribeStr; retCode = CMD_GENA_UNSUBSCRIBE; break; case 'N': pattern = notifyStr; retCode = CMD_GENA_UNSUBSCRIBE; break; default: // unknown method throw -1; } int patLength = strlen( pattern ); for ( i = 1; i < patLength; i++ ) { if ( line[i] != pattern[i] ) throw -1; } } catch ( OutOfBoundsException& e ) { return CMD_HTTP_UNKNOWN; } catch ( int parseCode ) { if ( parseCode == -1 ) { return CMD_HTTP_UNKNOWN; } } return retCode;}static int ParseContentLength( const xstring& textLine, bool& malformed ){ xstring line; xstring asciiNum; char *pattern = "CONTENT-LENGTH"; int patlen = strlen( pattern ); int i; int contentLength; malformed = false; contentLength = -1; line = textLine; line.toUppercase(); if ( strncmp(line.c_str(), pattern, patlen) != 0 ) { // unknown header return -1; } i = patlen; try { // skip whitespace while ( line[i] == ' ' || line [i] == '\t' ) { i++; } // ":" if ( line[i] != ':' ) { throw -1; } i++; char* invalidChar = NULL; contentLength = strtol( &line[i], &invalidChar, 10 ); // anything other than crlf or whitespace after number is invalid if ( *invalidChar != '\0' ) { // see if there is an invalid number while ( *invalidChar ) { char c; c = *invalidChar; if ( !(c == ' ' || c == '\t' || c == '\r' || c == '\n') ) { // invalid char in number throw -1; } invalidChar++; } } } catch ( OutOfBoundsException& e ) { malformed = true; return -1; } catch ( int errCode ) { if ( errCode == -1 ) { malformed = true; return -1; } } return contentLength; }static void ReadRequest( int sockfd, xstring& document, HTTP_COMMAND_TYPE& command ){ NetReader1 reader( sockfd ); xstring reqLine; xstring line; bool newlineNotFound; int status; HTTP_COMMAND_TYPE cmd; int contentLength; const int BUFSIZE = 3; char buf[ BUFSIZE + 1 ]; MiniServerReadException excep; document = ""; // read request-line status = reader.getLine( reqLine, newlineNotFound ); if ( status < 0 ) { // read error excep.setErrorCode( RCODE_NETWORK_READ_ERROR ); throw excep; } if ( newlineNotFound ) { // format error excep.setErrorCode( RCODE_MALFORMED_LINE ); throw excep; } cmd = GetCommandType( reqLine ); if ( cmd == CMD_HTTP_UNKNOWN ) { // unknown or unsupported cmd excep.setErrorCode( RCODE_METHOD_NOT_IMPLEMENTED ); throw excep; } document += reqLine; contentLength = -1; // init // read headers while ( true ) { status = reader.getLine( line, newlineNotFound ); if ( status < 0 ) { // network error excep.setErrorCode( RCODE_NETWORK_READ_ERROR ); throw excep; } if ( newlineNotFound ) { // bad format excep.setErrorCode( RCODE_MALFORMED_LINE ); throw excep; } // get content-length if not obtained already if ( contentLength < 0 ) { bool malformed; contentLength = ParseContentLength( line, malformed ); if ( malformed ) { excep.setErrorCode( RCODE_MALFORMED_LINE ); throw excep; } } document += line; // done ? if ( line == "\n" || line == "\r\n" ) { break; } } // must have body for POST and M-POST msgs if ( contentLength < 0 && (cmd == CMD_SOAP_POST || cmd == CMD_SOAP_MPOST) ) { // HTTP: length reqd excep.setErrorCode( RCODE_LENGTH_NOT_SPECIFIED ); throw excep; } if ( contentLength > 0 ) { int totalBytesRead = 0; // read body while ( true ) { int bytesRead; bytesRead = reader.readData( buf, BUFSIZE ); buf[ bytesRead ] = 0; // null terminate string if ( bytesRead > 0 ) { document.appendLimited( buf, bytesRead ); totalBytesRead += bytesRead; if ( totalBytesRead >= contentLength ) { // done reading data break; } } else if ( bytesRead == 0 ) { // done break; } else { // error reading excep.setErrorCode( RCODE_NETWORK_READ_ERROR ); throw excep; } } } command = cmd;}static void HandleError( int errCode, int sockfd ){ xstring errMsg; switch (errCode) { case RCODE_NETWORK_READ_ERROR: break; case RCODE_MALFORMED_LINE: errMsg = "400 Bad Request"; break; case RCODE_LENGTH_NOT_SPECIFIED: errMsg = "411 Length Required"; break; case RCODE_METHOD_NOT_ALLOWED: errMsg = "405 Method Not Allowed"; break; case RCODE_INTERNAL_SERVER_ERROR: errMsg = "500 Internal Server Error"; break; case RCODE_METHOD_NOT_IMPLEMENTED: errMsg = "511 Not Implemented"; break; default: DBG( printf( "HandleError: unknown code %d\n", errCode ); ) break; }; if ( errMsg.length() == 0 ) return; xstring msg; msg = "HTTP/1.1 "; msg += errMsg; msg += "\r\n\r\n"; // send msg WriteNetData( msg.c_str(), sockfd ); // dbg // sleep so that client does get connection reset //sleep( 3 ); /////// // dbg DBG( printf( "http error: %s\n", msg.c_str() ); ) ///////}static void MultiplexCommand( HTTP_COMMAND_TYPE cmd, const xstring& document, int sockfd ){ MiniServerCallback callback; switch ( cmd ) { case CMD_SOAP_POST: case CMD_SOAP_MPOST: callback = gSoapCallback; break; case CMD_GENA_NOTIFY: case CMD_GENA_SUBSCRIBE: case CMD_GENA_UNSUBSCRIBE: callback = gGenaCallback; break; case CMD_HTTP_GET: callback = gGetCallback; break; default: callback = NULL; } if ( callback == NULL ) { MiniServerReadException e( "callback not defined or unknown method" ); e.setErrorCode( RCODE_METHOD_NOT_IMPLEMENTED ); throw e; } callback( document.c_str(), sockfd );}static void HandleRequest( void *args ){ int sockfd; xstring document; HTTP_COMMAND_TYPE cmd; sockfd = (int) args; try { ReadRequest( sockfd, document, cmd ); // pass data to callback MultiplexCommand( cmd, document, sockfd ); //printf( "input document:\n%s\n", document.c_str() ); } catch ( MiniServerReadException& e ) { // dbg DBG( e.print(); ) DBG( printf( "error code = %d\n", e.getErrorCode() ); ) ////// HandleError( e.getErrorCode(), sockfd ); // destroy connection close( sockfd ); } }static void RunMiniServer( void* args ){ struct sockaddr_in clientAddr; int listenfd; listenfd = (int)args; try { while ( true ) { int connectfd; socklen_t clientLen; // dbg //printf( "Waiting...\n" ); /////// // get a client request while ( true ) { connectfd = accept( listenfd, (sockaddr*) &clientAddr, &clientLen ); if ( connectfd > 0 ) { // valid connection break; } if ( connectfd == -1 && errno == EINTR ) { // ignore interruption continue; } else { xstring errStr = "Error: RunMiniServer: accept(): "; errStr = strerror( errno ); throw BasicException( errStr.c_str() ); } } int sched_stat; sched_stat = tpool_Schedule( HandleRequest, (void*)connectfd ); if ( sched_stat < 0 ) { HandleError( RCODE_INTERNAL_SERVER_ERROR, connectfd ); } //HandleRequest( (void *)connectfd ); } } catch ( GenericException& e ) { e.print(); free(StartMiniServer); //temporarily crashes if //miniserver doesn't start up //needs a better way to detect this case }}int StartMiniServer( unsigned short listen_port ){ struct sockaddr_in serverAddr; int listenfd; int success; //printf("listen port: %d\n",listen_port); listenfd = socket( AF_INET, SOCK_STREAM, 0 ); if ( listenfd <= 0 ) { return -1; // error creating socket } bzero( &serverAddr, sizeof(serverAddr) ); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl( INADDR_ANY ); serverAddr.sin_port = htons( listen_port ); success = bind( listenfd, (sockaddr*)&serverAddr, sizeof(serverAddr) ); if ( success == -1 ) { return -1; // bind failed } success = listen( listenfd, 10 ); if ( success == -1 ) { return -1; // listen failed } tpool_Schedule( RunMiniServer, (void *)listenfd ); return 0;}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -