📄 miniserver.cpp
字号:
/////////////////////////////////////////////////////////////////////////////// Copyright (c) 2000 Intel Corporation// All rights reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are met://// * Redistributions of source code must retain the above copyright notice,// this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above copyright notice,// this list of conditions and the following disclaimer in the documentation// and/or other materials provided with the distribution.// * Neither name of Intel Corporation nor the names of its contributors// may be used to endorse or promote products derived from this software// without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE./////////////////////////////////////////////////////////////////////////////// $Revision: 1.2 $// $Date: 2001/08/15 18:17:31 $#include "../../inc/tools/config.h"#if EXCLUDE_MINISERVER == 0#include <arpa/inet.h>#include <netinet/in.h>#include <pthread.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <unistd.h>#include <assert.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <genlib/util/utilall.h>#include <genlib/util/util.h>#include <genlib/miniserver/miniserver.h>#include <genlib/tpool/scheduler.h>#include <genlib/tpool/interrupts.h>#include "upnp.h"#include "tools/config.h"// read timeout#define TIMEOUT_SECS 30enum MiniServerState { MSERV_IDLE, MSERV_RUNNING, MSERV_STOPPING };CREATE_NEW_EXCEPTION_TYPE( MiniServerReadException, BasicException, "MiniServerReadException" )enum READ_EXCEPTION_CODE { RCODE_SUCCESS = 0, RCODE_NETWORK_READ_ERROR = -1, RCODE_MALFORMED_LINE = -2, RCODE_LENGTH_NOT_SPECIFIED = -3, RCODE_METHOD_NOT_ALLOWED = -4, RCODE_INTERNAL_SERVER_ERROR = -5, RCODE_METHOD_NOT_IMPLEMENTED = -6, RCODE_TIMEDOUT = -7, }; enum HTTP_COMMAND_TYPE { CMD_HTTP_GET, CMD_SOAP_POST, CMD_SOAP_MPOST, CMD_GENA_SUBSCRIBE, CMD_GENA_UNSUBSCRIBE, CMD_GENA_NOTIFY, CMD_HTTP_UNKNOWN, CMD_HTTP_MALFORMED };// module varsstatic MiniServerCallback gGetCallback = NULL;static MiniServerCallback gSoapCallback = NULL;static MiniServerCallback gGenaCallback = NULL;static MiniServerState gMServState = MSERV_IDLE;static pthread_t gMServThread = 0;//////////////void SetHTTPGetCallback( MiniServerCallback callback ){ gGetCallback = callback;}MiniServerCallback GetHTTPGetCallback( void ){ return gGetCallback;}void SetSoapCallback( MiniServerCallback callback ){ gSoapCallback = callback;}MiniServerCallback GetSoapCallback( void ){ return gSoapCallback;}void SetGenaCallback( MiniServerCallback callback ){ gGenaCallback = callback;}MiniServerCallback GetGenaCallback( void ){ return gGenaCallback;}class NetReader1{public: NetReader1( int socketfd ); virtual ~NetReader1(); // throws MiniServerReadException.RCODE_TIMEDOUT int getChar( char& c ); // throws MiniServerReadException.RCODE_TIMEDOUT int getLine( xstring& s, bool& newlineNotFound ); // throws MiniServerReadException.RCODE_TIMEDOUT int readData( void* buf, size_t bufferLen ); int getMaxBufSize() const { return maxbufsize; } private: bool bufferHasData() const { return offset < buflen; } // throws MiniServerReadException.RCODE_TIMEDOUT ssize_t refillBuffer();private: enum { MAX_BUFFER_SIZE = 1024 * 2 };private: int sockfd; char data[MAX_BUFFER_SIZE + 1]; // extra byte for null terminator int offset; int buflen; int maxbufsize;};NetReader1::NetReader1( int socketfd ){ sockfd = socketfd; offset = 0; maxbufsize = MAX_BUFFER_SIZE; buflen = 0; data[maxbufsize] = 0;}NetReader1::~NetReader1(){}int NetReader1::getChar( char& c ){ int status; if ( !bufferHasData() ) { status = refillBuffer(); if ( status <= 0 ) return status; if ( !bufferHasData() ) return 0; } c = data[offset]; offset++; return 1; // length of data returned}int NetReader1::getLine( xstring& s, bool& newlineNotFound ){ int startOffset; char c; int status; bool crFound; startOffset = offset; s = ""; newlineNotFound = false; crFound = false; while ( true ) { status = getChar( c ); if ( status == 0 ) { // no more chars in stream newlineNotFound = true; return s.length(); } if ( status < 0 ) { // some kind of error return status; } s += c; if ( c == 0xA ) { return s.length(); } else if ( c == 0xD ) // CR { crFound = true; } else { // wanted to see LF after CR; error if ( crFound ) { newlineNotFound = true; return s.length(); } } } return 0;}// read dataint NetReader1::readData( void* buf, size_t bufferLen ){ int status; int copyLen; size_t dataLeft; // size of data left in buffer if ( bufferLen <= 0 ) return 0; // 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;}// throws MiniServerReadException.RCODE_TIMEDOUTstatic int SocketRead( int sockfd, char* buffer, size_t bufsize, int timeoutSecs ){ int retCode; fd_set readSet; struct timeval timeout; int numRead; assert( sockfd > 0 ); assert( buffer != NULL ); assert( bufsize > 0 ); FD_ZERO( &readSet ); FD_SET( sockfd, &readSet ); timeout.tv_sec = timeoutSecs; timeout.tv_usec = 0; while ( true ) { retCode = select( sockfd + 1, &readSet, NULL, NULL, &timeout ); if ( retCode == 0 ) { // timed out MiniServerReadException e( "SocketRead(): timed out" ); e.setErrorCode( RCODE_TIMEDOUT ); throw e; } if ( retCode == -1 ) { if ( errno == EINTR ) { continue; // ignore interrupts } return retCode; // error } else { break; } } // read data numRead = read( sockfd, buffer, bufsize ); return numRead;}ssize_t NetReader1::refillBuffer(){ ssize_t numRead; // old code // numRead = read( sockfd, data, maxbufsize ); /////// numRead = SocketRead( sockfd, data, maxbufsize, TIMEOUT_SECS ); 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_NOTIFY; 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -