Esempio n. 1
0
void DebugLevel_1(FILE*   statusFile, FILE*   stdOut,  Bool16 printHeader )
{
    char*  thePrefStr = NULL;
    static char numStr[12] ="";
    static char dateStr[25] ="";
    UInt32 theLen = 0;

    if ( printHeader )
    {                   
        printf("****************************************");
	}
       
    delete [] thePrefStr; thePrefStr = NULL;
    
    (void)QTSS_GetValueAsString(sServer, qtssCurrentSessionCount, 0, &thePrefStr);
    print_status(statusFile, stdOut,"%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;

    qtss_snprintf(numStr,sizeof(numStr) -1, "%"  _U32BITARG_  "", (SInt32) sServer->GetNumThinned() );
    print_status(statusFile, stdOut,"%11s", numStr);
 
    char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
    (void) QTSSRollingLog::FormatDate(theDateBuffer, false);
    
    qtss_snprintf(dateStr,sizeof(dateStr) -1, "%s", theDateBuffer );
    print_status(statusFile, stdOut,"%24s\n", dateStr);
}
Esempio n. 2
0
// This sends the HTTP response to the server that contains the RTSPtext Ref movie
QTSS_Error SendTheResponse(QTSS_RTSPSessionObject theSession, QTSS_StreamRef stream, StrPtrLen& movie)
{
    QTSS_Error err = QTSS_NoErr;
    char theMovieFile[512];
    theMovieFile[sizeof(theMovieFile) -1] = 0;
    
    char tmp[600];	
    tmp[sizeof(tmp) -1] = 0;
    
    char tmp2[80];
    tmp2[sizeof(tmp2) -1] = 0;
    
    UInt8 x1, x2, x3, x4;

    // send the HTTP reply header to the client
    err= QTSS_Write(stream, sResponseHeader, ::strlen(sResponseHeader), NULL, qtssWriteFlagsBufferData);
    if (err != QTSS_NoErr)
        return QTSS_NoErr;
   
    UInt32 ip4address = 0;
    UInt32 len = sizeof(ip4address);
    err = QTSS_GetValue(theSession, qtssRTSPSesLocalAddr, 0, &ip4address, &len);
        
	// Format the server IP address for building the RTSP address in the reply.
    x1 = (UInt8)((ip4address >> 24) & 0xff);
    x2 = (UInt8)((ip4address >> 16) & 0xff);
    x3 = (UInt8)((ip4address >> 8) & 0xff);
    x4 = (UInt8)((ip4address) & 0xff);
    
    if (movie.Len > sizeof(theMovieFile)  -1 )
        movie.Len = sizeof(theMovieFile) -1;
        
    ::memcpy(theMovieFile, movie.Ptr, movie.Len);
	theMovieFile[movie.Len] = '\0';
	
    UInt16 port = sRTSPReplyPort;
    if (0 == port)
    {
        len = sizeof(port);
        err = QTSS_GetValue(theSession, qtssRTSPSesLocalPort, 0, &port, &len);
    }
            
	// construct the RTSP address reply string for the client.
	qtss_snprintf(tmp,sizeof(tmp) -1, "rtsptext\r\nrtsp://%d.%d.%d.%d:%d%s\r\n", x1,x2,x3,x4, port, theMovieFile);
    
    // send the 'Content-Length:' part of the HTTP reply
    qtss_snprintf(tmp2, sizeof(tmp2) -1, "Content-Length: %d\r\n\r\n", (int) ::strlen(tmp));
    err = QTSS_Write(stream, tmp2, ::strlen(tmp2), NULL, qtssWriteFlagsBufferData);
    if (err != QTSS_NoErr)
        return QTSS_NoErr;
        
    // send the formatted RTSP reference part of the reply
    err = QTSS_Write(stream, tmp, ::strlen(tmp), NULL, qtssWriteFlagsBufferData);
    if (err != QTSS_NoErr)
        return QTSS_NoErr;
        
    // flush the pending write to the client.
    err = QTSS_Flush(stream);
    return err;
}
HTTPSessionInterface::~HTTPSessionInterface()
{
    // If the input socket is != output socket, the input socket was created dynamically
    if (fInputSocketP != fOutputSocketP)
        delete fInputSocketP;

    char remoteAddress[20] = { 0 };
    StrPtrLen theIPAddressStr(remoteAddress, sizeof(remoteAddress));
    QTSS_GetValue(this, EasyHTTPSesRemoteAddrStr, 0, static_cast<void*>(theIPAddressStr.Ptr), &theIPAddressStr.Len);
    char msgStr[2048] = { 0 };

    switch (fSessionType)
    {
    case EasyCameraSession:
        this->UnRegDevSession();
        qtss_snprintf(msgStr, sizeof(msgStr), "EasyCameraSession offline from ip[%s], device_serial[%s]", remoteAddress, device_->serial_.c_str());
        break;
    case EasyNVRSession:
        this->UnRegDevSession();
        qtss_snprintf(msgStr, sizeof(msgStr), "EasyNVRSession offline from ip[%s]", remoteAddress);
        break;
    case EasyHTTPSession:
        qtss_snprintf(msgStr, sizeof(msgStr), "EasyHTTPSession offline from ip[%s]", remoteAddress);
        break;
    default:
        qtss_snprintf(msgStr, sizeof(msgStr), "Unknown session offline from ip[%s]", remoteAddress);
        break;
    }
    QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);
}
void DoDescribeAddRequiredSDPLines2(QTSS_StandardRTSP_Params* inParams, ReflectorSession* theSession, QTSS_TimeVal modDate,  ResizeableStringFormatter *editedSDP, StrPtrLen* theSDPPtr)
{
    SDPContainer checkedSDPContainer;
    checkedSDPContainer.SetSDPBuffer( theSDPPtr );  
    if (!checkedSDPContainer.HasReqLines())
    {
        if (!checkedSDPContainer.HasLineType('v'))
        { // add v line
            editedSDP->Put("v=0\r\n");
        }
        
        if (!checkedSDPContainer.HasLineType('s'))
        { // add s line
           char* theSDPName = NULL;            
            (void)QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFilePath, 0, &theSDPName);
            QTSSCharArrayDeleter thePathStrDeleter(theSDPName);
            editedSDP->Put("s=");
            editedSDP->Put(theSDPName);
            editedSDP->PutEOL();
        }
        
       if (!checkedSDPContainer.HasLineType('t'))
       { // add t line
            editedSDP->Put("t=0 0\r\n");
       }

       if (!checkedSDPContainer.HasLineType('o'))
       { // add o line
            editedSDP->Put("o=broadcast_sdp ");
            char tempBuff[256]= "";               
            tempBuff[255] = 0;
            qtss_snprintf(tempBuff,sizeof(tempBuff) - 1, "%lu", (UInt64) theSession);
            editedSDP->Put(tempBuff);

            editedSDP->Put(" ");
            // modified date is in milliseconds.  Convert to NTP seconds as recommended by rfc 2327
            qtss_snprintf(tempBuff, sizeof(tempBuff) - 1, "%"_64BITARG_"d", (SInt64) (modDate/1000) + 2208988800LU);
            editedSDP->Put(tempBuff);

            editedSDP->Put(" IN IP4 ");
            UInt32 buffLen = sizeof(tempBuff) -1;
            (void)QTSS_GetValue(inParams->inClientSession, qtssCliSesHostName, 0, &tempBuff, &buffLen);
            editedSDP->Put(tempBuff, buffLen);

            editedSDP->PutEOL();
        }
    } 
    editedSDP->Put(*theSDPPtr);
}
Esempio n. 5
0
void    WriteStartupMessage()
{
    if (sStartedUp)
        return;
        
    sStartedUp = true;
    
    //format a date for the startup time
    char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
    Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
    
    char tempBuffer[kMaxLogStringLen];
    if (result)
        qtss_snprintf(tempBuffer,sizeof(tempBuffer), "# Streaming STARTUP %s\n", theDateBuffer);
        
    // log startup message to error log as well.
    if ((result) && (sErrorLog != NULL))
        sErrorLog->WriteToLog(tempBuffer, kAllowLogToRoll);
    
    //write the expire date to the log
    if ( QTSSExpirationDate::WillSoftwareExpire() && sErrorLog != NULL )
    {
        QTSSExpirationDate::sPrintExpirationDate(tempBuffer);
        sErrorLog->WriteToLog(tempBuffer, kAllowLogToRoll);
    }
}
Esempio n. 6
0
void FormattedTotalBytesBuffer(char *outBuffer, int outBufferLen, UInt64 totalBytes)
{
    Float32 displayBytes = 0.0;
    char  sizeStr[] = "B";
    char* format = NULL;
        
    if (totalBytes > 1073741824 ) //GBytes
    {   displayBytes = (Float32) ( (Float64) (SInt64) totalBytes /  (Float64) (SInt64) 1073741824 );
        sizeStr[0] = 'G';
        format = "%.4f%s ";
     }
    else if (totalBytes > 1048576 ) //MBytes
    {   displayBytes = (Float32) (SInt32) totalBytes /  (Float32) (SInt32) 1048576;
        sizeStr[0] = 'M';
        format = "%.3f%s ";
     }
    else if (totalBytes > 1024 ) //KBytes
    {    displayBytes = (Float32) (SInt32) totalBytes /  (Float32) (SInt32) 1024;
         sizeStr[0] = 'K';
         format = "%.2f%s ";
    }
    else
    {    displayBytes = (Float32) (SInt32) totalBytes;  //Bytes
         sizeStr[0] = 'B';
         format = "%4.0f%s ";
    }
    
    outBuffer[outBufferLen -1] = 0;
    qtss_snprintf(outBuffer, outBufferLen -1,  format , displayBytes, sizeStr);
}
Esempio n. 7
0
void RelaySession::Register()
{
    qtssRelaySessionObjectType = 0;
    
    // create relay session object type
    (void)QTSS_CreateObjectType(&qtssRelaySessionObjectType);
    
    // Add the static attributes to the qtssRelaySessionObjectType object
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sRelayNameName, NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sRelayNameName, &sRelayName);              // relay name
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceTypeName, NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceTypeName, &sSourceType);                // source type
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceIPAddrName, NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceIPAddrName, &sSourceIPAddr);            // source addr
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceInIPAddrName, NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceInIPAddrName, &sSourceInIPAddr);        // interface addr
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceUDPPortsName, NULL, qtssAttrDataTypeUInt16);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceUDPPortsName, &sSourceUDPPorts);        // udp ports
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceRTSPPortName, NULL, qtssAttrDataTypeUInt16);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceRTSPPortName, &sSourceRTSPPort);        // rtsp port
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceURLName, NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceURLName, &sSourceURL);                  // url
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceUsernameName, NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceUsernameName, &sSourceUsername);    // username
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourcePasswordName, NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourcePasswordName, &sSourcePassword);        // password
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sSourceTTLName, NULL, qtssAttrDataTypeUInt16);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sSourceTTLName, &sSourceTTL);                  // ttl
    
    (void)QTSS_AddStaticAttribute(qtssRelaySessionObjectType, sRelayOutputObjectName, NULL, qtssAttrDataTypeQTSS_Object);
    (void)QTSS_IDForAttr(qtssRelaySessionObjectType, sRelayOutputObjectName, &sRelayOutputObject);  // relay output
        
    //char* strEnd        = NULL;
    char* relayStr = "QTSS_Relay/";
    //kVersionString is changed now -- it doesn't contain any spaces or the build number
    //strEnd = strchr(kVersionString, ' ');
    //Assert(strEnd != NULL);
#ifndef __Win32__
    //qtss_snprintf(sRelayUserAgent, ::strlen(relayStr) + (strEnd - kVersionString) + 1, "%s/%s", relayStr, kVersionString);
    qtss_snprintf(sRelayUserAgent, ::strlen(relayStr) + ::strlen(kVersionString) + 1, "%s%s", relayStr, kVersionString);
#else
    //_snprintf(sRelayUserAgent, ::strlen(relayStr) + (strEnd - kVersionString) + 1, "%s/%s", relayStr, kVersionString);
    _snprintf(sRelayUserAgent, ::strlen(relayStr) + ::strlen(kVersionString) + 1, "%s%s", relayStr, kVersionString);
#endif        
}
Esempio n. 8
0
void QTSSModuleUtils::LogPrefErrorStr( QTSS_ErrorVerbosity inVerbosity, char*  preference, char* inMessage)
{  	
	if (inMessage == NULL || preference == NULL) 
	{  Assert(0);
	   return;  
	}
	char buffer[1024];
	
	qtss_snprintf(buffer,sizeof(buffer), "Server preference %s %s",  preference, inMessage);
   
	(void)QTSS_Write(sErrorLog, buffer, ::strlen(buffer), NULL, inVerbosity);
}
void RTSPRequestInterface::AppendContentLength(UInt32 contentLength)
{
    if (!fStandardHeadersWritten)
        this->WriteStandardHeaders();

    char dataSize[10];
    dataSize[sizeof(dataSize) -1] = 0;
    qtss_snprintf(dataSize, sizeof(dataSize) -1, "%lu", contentLength);
    StrPtrLen contentLengthStr(dataSize);
    this->AppendHeader(qtssContentLengthHeader, &contentLengthStr);
    
}
Esempio n. 10
0
void    WriteShutdownMessage()
{
    if (!sStartedUp)
        return;
        
    sStartedUp = false;
    
    //log shutdown message
    //format a date for the shutdown time
    char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
    Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
    
    char tempBuffer[kMaxLogStringLen];
    if (result)
        qtss_snprintf(tempBuffer, sizeof(tempBuffer), "# Streaming SHUTDOWN %s\n", theDateBuffer);

    if ( result && sErrorLog != NULL )
        sErrorLog->WriteToLog(tempBuffer, kAllowLogToRoll);
}
Esempio n. 11
0
QTSS_Error  QTSSModule::SetupModule(QTSS_CallbacksPtr inCallbacks, QTSS_MainEntryPointPtr inEntrypoint)
{
	QTSS_Error theErr = QTSS_NoErr;

	// Load fragment from disk if necessary

	if ((fFragment != NULL) && (inEntrypoint == NULL))
		theErr = this->LoadFromDisk(&inEntrypoint);
	if (theErr != QTSS_NoErr)
		return theErr;

	// At this point, we must have an entrypoint
	if (inEntrypoint == NULL)
		return QTSS_NotAModule;

	// Invoke the private initialization routine
	QTSS_PrivateArgs thePrivateArgs;
	thePrivateArgs.inServerAPIVersion = QTSS_API_VERSION;
	thePrivateArgs.inCallbacks = inCallbacks;
	thePrivateArgs.outStubLibraryVersion = 0;
	thePrivateArgs.outDispatchFunction = NULL;

	theErr = (inEntrypoint)(&thePrivateArgs);
	if (theErr != QTSS_NoErr)
		return theErr;

	if (thePrivateArgs.outStubLibraryVersion > thePrivateArgs.inServerAPIVersion)
		return QTSS_WrongVersion;

	// Set the dispatch function so we'll be able to invoke this module later on

	fDispatchFunc = thePrivateArgs.outDispatchFunction;

	//Log 
	char msgStr[2048];
	char* moduleName = NULL;
	(void)this->GetValueAsString(qtssModName, 0, &moduleName);
	qtss_snprintf(msgStr, sizeof(msgStr), "Loading Module...%s [%s]", moduleName, (fFragment == NULL) ? "static" : "dynamic");
	delete moduleName;
	QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);

	return QTSS_NoErr;
}
Esempio n. 12
0
Bool16 XMLParser::ParseFile(char* errorBuffer, int errorBufferSize)
{
    if (fRootTag != NULL)
    {
        delete fRootTag;    // flush old data
        fRootTag = NULL;
    }
    
    fFile.Set(fFilePath);

    if (errorBufferSize < 500) errorBuffer = NULL;  // Just a hack to avoid checking everywhere
    if ((fFile.GetLength() == 0) || fFile.IsDir())
    {
        if (errorBuffer != NULL)
            qtss_snprintf(errorBuffer, errorBufferSize,  "Couldn't read xml file");
        return false;   // we don't have a valid file;
    }
    
    char* fileData = NEW char[ (SInt32) (fFile.GetLength() + 1)];
    UInt32 theLengthRead = 0;
    fFile.Read(0, fileData, (UInt32) fFile.GetLength(), &theLengthRead); 

    StrPtrLen theDataPtr(fileData, theLengthRead);
    StringParser theParser(&theDataPtr);
    
    fRootTag = NEW XMLTag();
    Bool16 result = fRootTag->ParseTag(&theParser, fVerifier, errorBuffer, errorBufferSize);
    if (!result)
    {
        // got error parsing file
        delete fRootTag;
        fRootTag = NULL;
    }
    
    delete []fileData;
    
    fFile.Close();

    return result;
}
Esempio n. 13
0
CServiceSession::~CServiceSession()
{
	char remoteAddress[20] = {0};
	StrPtrLen theIPAddressStr(remoteAddress,sizeof(remoteAddress));
	QTSS_GetValue(this, qtssRTSPSesRemoteAddrStr, 0, (void*)theIPAddressStr.Ptr, &theIPAddressStr.Len);

	char msgStr[2048] = { 0 };
	qtss_snprintf(msgStr, sizeof(msgStr), "session offline from ip[%s]",remoteAddress);
	QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);
    // Invoke the session closing modules
    QTSS_RoleParams theParams;
    theParams.rtspSessionClosingParams.inRTSPSession = this;
    
    //会话断开时,调用模块进行一些停止的工作
    for (UInt32 x = 0; x < QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPSessionClosingRole); x++)
        (void)QTSServerInterface::GetModule(QTSSModule::kRTSPSessionClosingRole, x)->CallDispatch(QTSS_RTSPSessionClosing_Role, &theParams);

    fLiveSession = false; //used in Clean up request to remove the RTP session.
    this->CleanupRequest();// Make sure that all our objects are deleted
    //if (fSessionType == qtssServiceSession)
    //    QTSServerInterface::GetServer()->AlterCurrentServiceSessionCount(-1);
}
void HTTPSessionInterface::UnRegDevSession()
{
	if (fAuthenticated)
	{
		char msgStr[512];
		qtss_snprintf(msgStr, sizeof(msgStr), "Device unregister,Device_serial[%s]\n", fDevice.serial_.c_str());
		QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);

		QTSServerInterface::GetServer()->GetDeviceSessionMap()->UnRegister(fDevice.serial_);//add
		//在redis上删除设备
		//QTSServerInterface::GetServer()->RedisDelDevName(fDevice.serial_.c_str());

		QTSS_RoleParams theParams;
		theParams.StreamNameParams.inStreamName = (char *)(fDevice.serial_.c_str());
		UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kDelDevNameRole);
		for ( UInt32 currentModule=0;currentModule < numModules; currentModule++)
		{
			QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kDelDevNameRole, currentModule);
			(void)theModule->CallDispatch(QTSS_DelDevName_Role, &theParams);
		}
	}
}
void HTTPSessionInterface::UnRegDevSession() const
{
    if (fAuthenticated)
    {
        char msgStr[512];
        qtss_snprintf(msgStr, sizeof(msgStr), "Device unregister£¬Device_serial[%s]\n", device_->serial_.c_str());
        QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);

        QTSServerInterface::GetServer()->GetDeviceSessionMap()->UnRegister(device_->serial_);//add
        //ÔÚredisÉÏɾ³ýÉ豸
        //QTSServerInterface::GetServer()->RedisDelDevice(fDevice.serial_.c_str());

        QTSS_RoleParams theParams;
		theParams.DeviceInfoParams.serial_ = new char[64];
		strncpy(theParams.DeviceInfoParams.serial_, device_->serial_.c_str(), device_->serial_.size() + 1);
        UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRedisDelDeviceRole);
        for (UInt32 currentModule = 0; currentModule < numModules; currentModule++)
        {
            QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kRedisDelDeviceRole, currentModule);
            (void)theModule->CallDispatch(Easy_RedisDelDevice_Role, &theParams);
        }
		delete[] theParams.DeviceInfoParams.serial_;
    }
}
Esempio n. 16
0
void TCPListenerSocket::ProcessEvent(int /*eventBits*/)
{
    //we are executing on the same thread as every other
    //socket, so whatever you do here has to be fast.
    
    struct sockaddr_in addr;
#if __Win32__ || __osf__ || __sgi__ || __hpux__	
    int size = sizeof(addr);
#else
    socklen_t size = sizeof(addr);
#endif
    Task* theTask = NULL;
    TCPSocket* theSocket = NULL;
    
    //fSocket data member of TCPSocket.
	int osSocket = accept(fFileDesc, (struct sockaddr*)&addr, &size);

//test osSocket = -1;
	if (osSocket == -1)
	{
        //take a look at what this error is.
        int acceptError = OSThread::GetErrno();
        if (acceptError == EAGAIN)
        { 
            //If it's EAGAIN, there's nothing on the listen queue right now,
            //so modwatch and return
            this->RequestEvent(EV_RE);
            return;
        }
		
//test acceptError = ENFILE;
//test acceptError = EINTR;
//test acceptError = ENOENT;
		 
        //if these error gets returned, we're out of file desciptors, 
        //the server is going to be failing on sockets, logs, qtgroups and qtuser auth file accesses and movie files. The server is not functional.
		if (acceptError == EMFILE || acceptError == ENFILE)
        {           
#ifndef __Win32__

			QTSSModuleUtils::LogErrorStr(qtssFatalVerbosity,  "Out of File Descriptors. Set max connections lower and check for competing usage from other processes. Exiting.");
#endif

			exit (EXIT_FAILURE);	
        }
        else
        {   
            char errStr[256];
            errStr[sizeof(errStr) -1] = 0;
            qtss_snprintf(errStr, sizeof(errStr) -1, "accept error = %d '%s' on socket. Clean up and continue.", acceptError, strerror(acceptError)); 
            WarnV( (acceptError == 0), errStr);
            
            theTask = this->GetSessionTask(&theSocket);
            if (theTask == NULL)
            {   
                close(osSocket);
            }
            else
            {  
                theTask->Signal(Task::kKillEvent); // just clean up the task
            }
            
            if (theSocket)
                theSocket->fState &= ~kConnected; // turn off connected state
            
            return;
        }
	}
	
    theTask = this->GetSessionTask(&theSocket);
    if (theTask == NULL)
    {    //this should be a disconnect. do an ioctl call?
        close(osSocket);
        if (theSocket)
            theSocket->fState &= ~kConnected; // turn off connected state
    }
    else
    {   
        Assert(osSocket != EventContext::kInvalidFileDesc);
        
        //set options on the socket
        //we are a server, always disable nagle algorithm
        int one = 1;
        int err = ::setsockopt(osSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int));
        AssertV(err == 0, OSThread::GetErrno());
        
        err = ::setsockopt(osSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(int));
        AssertV(err == 0, OSThread::GetErrno());
    
        int sndBufSize = 96L * 1024L;
        err = ::setsockopt(osSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sndBufSize, sizeof(int));
        AssertV(err == 0, OSThread::GetErrno());
    
        //setup the socket. When there is data on the socket,
        //theTask will get an kReadEvent event
        theSocket->Set(osSocket, &addr);
        theSocket->InitNonBlocking(osSocket);
        theSocket->SetTask(theTask);
        theSocket->RequestEvent(EV_RE);
        
        theTask->SetThreadPicker(Task::GetBlockingTaskThreadPicker()); //The RTSP Task processing threads
    }
    


    if (fSleepBetweenAccepts)
    { 	
        // We are at our maximum supported sockets
        // slow down so we have time to process the active ones (we will respond with errors or service).
        // wake up and execute again after sleeping. The timer must be reset each time through
        //qtss_printf("TCPListenerSocket slowing down\n");
        this->SetIdleTimer(kTimeBetweenAcceptsInMsec); //sleep 1 second
    }
    else
    { 	
        // sleep until there is a read event outstanding (another client wants to connect)
        //qtss_printf("TCPListenerSocket normal speed\n");
        this->RequestEvent(EV_RE);
    }

    fOutOfDescriptors = false; // always false for now  we don't properly handle this elsewhere in the code
}
Esempio n. 17
0
SDPLineSorter::SDPLineSorter(SDPContainer *rawSDPContainerPtr, Float32 adjustMediaBandwidthPercent, SDPContainer *insertMediaLinesArray) : fSessionLineCount(0), fSDPSessionHeaders(NULL, 0), fSDPMediaHeaders(NULL, 0)
{

	Assert(rawSDPContainerPtr != NULL);
	if (NULL == rawSDPContainerPtr)
		return;

	StrPtrLen theSDPData(rawSDPContainerPtr->fSDPBuffer.Ptr, rawSDPContainerPtr->fSDPBuffer.Len);
	StrPtrLen *theMediaStart = rawSDPContainerPtr->GetLine(rawSDPContainerPtr->FindHeaderLineType('m', 0));
	if (theMediaStart && theMediaStart->Ptr && theSDPData.Ptr)
	{
		UInt32  mediaLen = theSDPData.Len - (UInt32)(theMediaStart->Ptr - theSDPData.Ptr);
		char *mediaStartPtr = theMediaStart->Ptr;
		fMediaHeaders.Set(mediaStartPtr, mediaLen);
		StringParser sdpParser(&fMediaHeaders);
		SDPLine sdpLine;
		Bool16 foundLine = false;
		Bool16 newMediaSection = true;
		SDPLine* insertLine = NULL;

		while (sdpParser.GetDataRemaining() > 0)
		{
			foundLine = sdpParser.GetThruEOL(&sdpLine);
			if (!foundLine)
			{
				break;
			}
			if (sdpLine.GetHeaderType() == 'm')
				newMediaSection = true;

			if (insertMediaLinesArray && newMediaSection && (sdpLine.GetHeaderType() == 'a'))
			{
				newMediaSection = false;
				for (insertLine = insertMediaLinesArray->GetLine(0); insertLine; insertLine = insertMediaLinesArray->GetNextLine())
					fSDPMediaHeaders.Put(*insertLine);
			}

			if (('b' == sdpLine.GetHeaderType()) && (1.0 != adjustMediaBandwidthPercent))
			{
				StringParser bLineParser(&sdpLine);
				bLineParser.ConsumeUntilDigit();
				UInt32 bandwidth = (UInt32)(.5 + (adjustMediaBandwidthPercent * (Float32)bLineParser.ConsumeInteger()));
				if (bandwidth < 1)
					bandwidth = 1;

				char bandwidthStr[10];
				qtss_snprintf(bandwidthStr, sizeof(bandwidthStr) - 1, "%"   _U32BITARG_   "", bandwidth);
				bandwidthStr[sizeof(bandwidthStr) - 1] = 0;

				fSDPMediaHeaders.Put(sMaxBandwidthTag);
				fSDPMediaHeaders.Put(bandwidthStr);
			}
			else
				fSDPMediaHeaders.Put(sdpLine);

			fSDPMediaHeaders.Put(SDPLineSorter::sEOL);
		}
		fMediaHeaders.Set(fSDPMediaHeaders.GetBufPtr(), fSDPMediaHeaders.GetBytesWritten());
	}

	fSessionLineCount = rawSDPContainerPtr->FindHeaderLineType('m', 0);
	if (fSessionLineCount < 0) // didn't find it use the whole buffer
	{
		fSessionLineCount = rawSDPContainerPtr->GetNumLines();
	}

	for (SInt16 sessionLineIndex = 0; sessionLineIndex < fSessionLineCount; sessionLineIndex++)
		fSessionSDPContainer.AddHeaderLine((StrPtrLen *)rawSDPContainerPtr->GetLine(sessionLineIndex));

	//qtss_printf("\nSession raw Lines:\n"); fSessionSDPContainer.PrintAllLines();

	SInt16 numHeaderTypes = sizeof(SDPLineSorter::sSessionOrderedLines) - 1;
	Bool16 addLine = true;
	for (SInt16 fieldTypeIndex = 0; fieldTypeIndex < numHeaderTypes; fieldTypeIndex++)
	{
		SInt32 lineIndex = fSessionSDPContainer.FindHeaderLineType(SDPLineSorter::sSessionOrderedLines[fieldTypeIndex], 0);
		StrPtrLen *theHeaderLinePtr = fSessionSDPContainer.GetLine(lineIndex);

		while (theHeaderLinePtr != NULL)
		{
			addLine = this->ValidateSessionHeader(theHeaderLinePtr);
			if (addLine)
			{
				fSDPSessionHeaders.Put(*theHeaderLinePtr);
				fSDPSessionHeaders.Put(SDPLineSorter::sEOL);
			}

			if (NULL != ::strchr(sessionSingleLines, theHeaderLinePtr->Ptr[0])) // allow 1 of this type: use first found
				break; // move on to next line type

			lineIndex = fSessionSDPContainer.FindHeaderLineType(SDPLineSorter::sSessionOrderedLines[fieldTypeIndex], lineIndex + 1);
			theHeaderLinePtr = fSessionSDPContainer.GetLine(lineIndex);
		}
	}
	fSessionHeaders.Set(fSDPSessionHeaders.GetBufPtr(), fSDPSessionHeaders.GetBytesWritten());

}
Esempio n. 18
0
QTSS_Error Authenticate(QTSS_StandardRTSP_Params* inParams)
{

    if  ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) ) {
        return QTSS_RequestFailed;
    }
    
    QTSS_RTSPRequestObject  theRTSPRequest = inParams->inRTSPRequest;
    QTSS_Error theErr = QTSS_NoErr;
        
    char *movieUrlTrunc = NULL;
    theErr = QTSS_GetValueAsString(theRTSPRequest,qtssRTSPReqTruncAbsoluteURL, 0, &movieUrlTrunc);
    QTSSCharArrayDeleter movieUrlTruncDeleter(movieUrlTrunc);
    if (theErr != QTSS_NoErr)
        return QTSS_RequestFailed;

    char *movieUrlFilename = NULL;
    theErr = QTSS_GetValueAsString(theRTSPRequest,qtssRTSPReqFileName, 0, &movieUrlFilename);
    QTSSCharArrayDeleter movieUrlFilenameDeleter(movieUrlFilename);
    if (theErr != QTSS_NoErr)
        return QTSS_RequestFailed;
    
    // Return unless the requested filename matches the redirect URL
    if (::strncmp(movieUrlFilename, sRedirectUrl,  (::strlen(movieUrlFilename) <= ::strlen(sRedirectUrl)) 
            ? ::strlen(sRedirectUrl) : ::strlen(movieUrlFilename)))
        return QTSS_NoErr;
    
    // Get the client's bandwidth header
    UInt32 bandwidthBits = 0;
    UInt32 len = sizeof(bandwidthBits);
	(void)QTSS_GetValue(theRTSPRequest, qtssRTSPReqBandwidthBits, 0, (void *)&bandwidthBits, &len);

    // Prepare a filename extension to use for redirection.
    // These numbers match the "Streaming Speed" options in the QuickTime Player 7 settings.
    // The extension will be appended to the requested URL.
    char theNewFilename[kBuffSize];
    ::memset(theNewFilename, 0, kBuffSize);
    
    if (bandwidthBits <= 0) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_50kbit.3gp", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 28000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_50kbit.3gp", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 56000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_50kbit.3gp", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 112000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_100kbit.mov", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 256000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_100kbit.mov", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 384000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_300kbit.mov", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 512000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_300kbit.mov", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 768000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_300kbit.mov", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 1000000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_h264_1mbit.mp4", movieUrlTrunc, movieUrlFilename);
    } else if (bandwidthBits <= 1500000) {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_h264_1mbit.mp4", movieUrlTrunc, movieUrlFilename);
    } else {
        qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_h264_1mbit.mp4", movieUrlTrunc, movieUrlFilename);
    }
    
    // In order to send the redirect, we need to get a QTSS_StreamRef
    // so we can send data to the client. Get the QTSS_StreamRef out of the request.
    QTSS_StreamRef* theStreamRef = NULL;
    UInt32 strRefLen = 0;
        
    theErr = QTSS_GetValuePtr(theRTSPRequest, qtssRTSPReqStreamRef, 0,
        (void**)&theStreamRef, &strRefLen);
    if (( QTSS_NoErr != theErr ) || ( sizeof(QTSS_StreamRef) != strRefLen) ) {
        return QTSS_RequestFailed;
    }

    // Send the redirect
    UInt32 theLenWritten = 0;
    
    (void)QTSS_Write(*theStreamRef, sRedirect.Ptr, sRedirect.Len, &theLenWritten, 0);
    (void)QTSS_Write(*theStreamRef, sLocation.Ptr, sLocation.Len, &theLenWritten, 0);
    (void)QTSS_Write(*theStreamRef, theNewFilename, ::strlen(theNewFilename), &theLenWritten, 0);
    (void)QTSS_Write(*theStreamRef, sRedirectEnd.Ptr, sRedirectEnd.Len, &theLenWritten, 0);
    (void)QTSS_Flush(*theStreamRef);
     
    return QTSS_NoErr;
}
Esempio n. 19
0
//启动服务
QTSS_ServerState StartServer(XMLPrefsParser* inPrefsSource, PrefsSource* inMessagesSource, UInt16 inPortOverride, int statsUpdateInterval, QTSS_ServerState inInitialState, Bool16 inDontFork, UInt32 debugLevel, UInt32 debugOptions)
{
    //Mark when we are done starting up. If auto-restart is enabled, we want to make sure
    //to always exit with a status of 0 if we encountered a problem WHILE STARTING UP. This
    //will prevent infinite-auto-restart-loop type problems
    Bool16 doneStartingUp = false;
    QTSS_ServerState theServerState = qtssStartingUpState;
    
	//服务单元状态更新间隔
    sStatusUpdateInterval = statsUpdateInterval;
    
    //Initialize utility classes
    OS::Initialize();
    OSThread::Initialize();
	
	//建立网络事件(R/W/E事件)线程,仅建立,But未启动
    Socket::Initialize();
	//获取系统网卡数量sNumIPAddrs及对应的具体ip,存储在sIPAddrInfoArray结构体数组中
    SocketUtils::Initialize(!inDontFork);
/*
#if !MACOSXEVENTQUEUE
    ::select_startevents();//initialize the select() implementation of the event queue
#endif
*/
    #if !MACOSXEVENTQUEUE
#ifndef __Win32__    
    ::epollInit();
#else
    ::select_startevents();//initialize the select() implementation of the event queue        
#endif

#endif
	//初始化系统属性字典
    QTSSDictionaryMap::Initialize();
	//初始化Server对象属性字典,包括其他具有属性字典的类,都要先进行Initialize
    QTSServerInterface::Initialize();//此部分必须在QTSServer对象构造前调用
	sServer = NEW QTSServer();
    sServer->SetDebugLevel(debugLevel);
    sServer->SetDebugOptions(debugOptions);
    
    //重新解析xml配置
    inPrefsSource->Parse();

	//准备开启监听,接收并处理相关事务
    Bool16 createListeners = true;
    if (qtssShuttingDownState == inInitialState) 
		createListeners = false;
    
	//初始化服务实例
    sServer->Initialize(inPrefsSource, inMessagesSource, inPortOverride, createListeners);

    if (inInitialState == qtssShuttingDownState)
    {  
        sServer->InitModules(inInitialState);
        return inInitialState;
    }

    if (sServer->GetServerState() != qtssFatalErrorState)
    {
        UInt32 numShortTaskThreads = 0;
        UInt32 numBlockingThreads = 0;
        UInt32 numThreads = 0;
        UInt32 numProcessors = 0;
        
        if (OS::ThreadSafe())
        {
			//工作线程
            numShortTaskThreads = sServer->GetPrefs()->GetNumThreads(); // whatever the prefs say
            if (numShortTaskThreads == 0) {
               numProcessors = OS::GetNumProcessors();
                // 1 worker thread per processor, up to 2 threads.
                // Note:Limiting the number of worker threads to 2 on a MacOS X system with > 2 cores
                //		results in better performance on those systems, as of MacOS X 10.5.  Future
                //		improvements should make this limit unnecessary.
                if (numProcessors > 2)
                    numShortTaskThreads = 2;
                else
                    numShortTaskThreads = numProcessors;
            }

			//协议处理线程
            numBlockingThreads = sServer->GetPrefs()->GetNumBlockingThreads(); // whatever the prefs say
            if (numBlockingThreads == 0)
                numBlockingThreads = 1;
                
        }
        if (numShortTaskThreads == 0)
            numShortTaskThreads = 1;

        if (numBlockingThreads == 0)
            numBlockingThreads = 1;

        numThreads = numShortTaskThreads + numBlockingThreads;
        //qtss_printf("Add threads shortask=%lu blocking=%lu\n",numShortTaskThreads, numBlockingThreads);
        TaskThreadPool::SetNumShortTaskThreads(numShortTaskThreads);
        TaskThreadPool::SetNumBlockingTaskThreads(numBlockingThreads);
        TaskThreadPool::AddThreads(numThreads);
		sServer->InitNumThreads(numThreads);
		
    #if DEBUG
        qtss_printf("Number of task threads: %" _U32BITARG_ "\n",numThreads);
    #endif
    
        // Start up the server's global tasks, and start listening
		//超时事件处理线程
        TimeoutTask::Initialize();  // The TimeoutTask mechanism is task based,
                                    // we therefore must do this after adding task threads
                                    // this be done before starting the sockets and server tasks
     }

    //Make sure to do this stuff last. Because these are all the threads that
    //do work in the server, this ensures that no work can go on while the server
    //is in the process of staring up
    if (sServer->GetServerState() != qtssFatalErrorState)
    {
		//Idle事务处理线程
        IdleTask::Initialize();
        Socket::StartThread();
        OSThread::Sleep(1000);
        
        //
        // On Win32, in order to call modwatch the Socket EventQueue thread must be
        // created first. Modules call modwatch from their initializer, and we don't
        // want to prevent them from doing that, so module initialization is separated
        // out from other initialization, and we start the Socket EventQueue thread first.
        // The server is still prevented from doing anything as of yet, because there
        // aren't any TaskThreads yet.
        sServer->InitModules(inInitialState);
        sServer->StartTasks();
        theServerState = sServer->GetServerState();
    }

    if (theServerState != qtssFatalErrorState)
    {
        CleanPid(true);
        WritePid(!inDontFork);
        doneStartingUp = true;

		//Log 
		char msgStr[128];
		qtss_snprintf(msgStr, sizeof(msgStr), "EasyCMS Service done starting up");
		QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);

        OSMemory::SetMemoryError(ENOMEM);
    }

    //// SWITCH TO RUN USER AND GROUP ID
    //if (!sServer->SwitchPersonality())
    //    theServerState = qtssFatalErrorState;

    // Tell the caller whether the server started up or not
    return theServerState;
}
MP3Broadcaster::MP3Broadcaster(char* ipaddr, int port, char* config, char* playList, char* workingDir, Bool16 useICY) :
    mValid(true),
    mPort(8000),
    mBitRate(0),
    mFrequency(0),
    mUpcomingSongsListSize(7),
    mRecentSongsListSize(0),
    mLogging(0),
    mShowCurrent(true),
    mShowUpcoming(true),
    mNumErrors(0),
    mNumWarnings(0),
    mPreflight(false),
    mCleanupDone(false),
    mTempPicker(NULL),
    mSocket(NULL, 0),
    mLog(NULL),
    mUseICY(useICY)
{
    sBroadcaster = this;
    
    strcpy(mIPAddr, "128.0.0.1");
    strcpy(mPlayListPath, DEFAULTPATHS_ETC_DIR "mp3playlist.ply");
    strcpy(mWorkingDirPath, DEFAULTPATHS_ETC_DIR);
    strcpy(mPlayMode, "sequential");
    strcpy(mMountPoint, "/");
    strcpy(mGenre, "Pop");
    strcpy(mURL, "");
    strcpy(mPIDFile, "");

    //see if there is a defaults File.
    //if there is load it and over-ride the other defaults
    int len = ::strlen(config) + 10;
    char *defaultFileName = new char[len];
    qtss_snprintf(defaultFileName, len, "%s%s", config, ".def");
    (void) ::ParseConfigFile( false, defaultFileName, ConfigSetter, this ); //ignore if no defaults file
    delete [] defaultFileName;
 
    int err = ::ParseConfigFile( false, config, ConfigSetter, this );
    if (err)
    {
        mValid = false;
        return;
    }
    
    if (ipaddr != NULL)
    {
        // override config file
        // size limit for any IP addr is 255
        strncpy(mIPAddr, ipaddr, 255);
    }
    
    if (port != 0)
    {
        // override config file
        mPort = port;
    }
    
    if (playList)
    {
        // override config file
        // size limit for any playlist string is PATH_MAX - 1
        strncpy(mPlayListPath, playList, PATH_MAX-1);
    }
    
    if (workingDir)
    {
        // override config file
        // size limit for any working path is PATH_MAX - extension - 1
        strncpy(mWorkingDirPath, playList, PATH_MAX-12);
    }
    
    CreateWorkingFilePath(".current", mCurrentFile);
    CreateWorkingFilePath(".upcoming", mUpcomingFile);
    CreateWorkingFilePath(".replacelist", mReplaceFile);
    CreateWorkingFilePath(".stoplist", mStopFile);
    CreateWorkingFilePath(".insertlist", mInsertFile);
    CreateWorkingFilePath("mp3_broadcast.log", mLogFile);
}
Esempio n. 21
0
void DebugLevel_1(FILE*   statusFile, FILE*   stdOut,  Bool16 printHeader )
{
    char*  thePrefStr = NULL;
    static char numStr[12] ="";
    static char dateStr[25] ="";
    UInt32 theLen = 0;

    if ( printHeader )
    {                   
   
        print_status(statusFile,stdOut,"%s", "     RTP-Conns RTSP-Conns HTTP-Conns  kBits/Sec   Pkts/Sec   RTP-Playing   AvgDelay CurMaxDelay  MaxDelay  AvgQuality  NumThinned      Time\n");

    }
    
    (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurConn, 0, &thePrefStr);
    print_status(statusFile, stdOut,"%11s", thePrefStr);
    
    delete [] thePrefStr; thePrefStr = NULL;
    
    (void)QTSS_GetValueAsString(sServer, qtssRTSPCurrentSessionCount, 0, &thePrefStr);
    print_status(statusFile, stdOut,"%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;
    
    (void)QTSS_GetValueAsString(sServer, qtssRTSPHTTPCurrentSessionCount, 0, &thePrefStr);
    print_status(statusFile, stdOut,"%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;
    
    UInt32 curBandwidth = 0;
    theLen = sizeof(curBandwidth);
    (void)QTSS_GetValue(sServer, qtssRTPSvrCurBandwidth, 0, &curBandwidth, &theLen);
    qtss_snprintf(numStr, 11, "%"_U32BITARG_"", curBandwidth/1024);
    print_status(statusFile, stdOut,"%11s", numStr);

    (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurPackets, 0, &thePrefStr);
    print_status(statusFile, stdOut,"%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;


    UInt32 currentPlaying = sServer->GetNumRTPPlayingSessions();
    qtss_snprintf( numStr, sizeof(numStr) -1, "%"_U32BITARG_"", currentPlaying);
    print_status(statusFile, stdOut,"%14s", numStr);

   
    //is the server keeping up with the streams?
    //what quality are the streams?
    SInt64 totalRTPPaackets = sServer->GetTotalRTPPackets();
    SInt64 deltaPackets = totalRTPPaackets - sLastDebugPackets;
    sLastDebugPackets = totalRTPPaackets;

    SInt64 totalQuality = sServer->GetTotalQuality();
    SInt64 deltaQuality = totalQuality - sLastDebugTotalQuality;
    sLastDebugTotalQuality = totalQuality;

    SInt64 currentMaxLate =  sServer->GetCurrentMaxLate();
    SInt64 totalLate =  sServer->GetTotalLate();

    sServer->ClearTotalLate();
    sServer->ClearCurrentMaxLate();
    sServer->ClearTotalQuality();
    
    ::qtss_snprintf(numStr, sizeof(numStr) -1, "%s", "0");
    if (deltaPackets > 0)
        qtss_snprintf(numStr, sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) ((SInt64)totalLate /  (SInt64) deltaPackets ));
    print_status(statusFile, stdOut,"%11s", numStr);

    qtss_snprintf(numStr,sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) currentMaxLate);
    print_status(statusFile, stdOut,"%11s", numStr);
    
    qtss_snprintf(numStr,sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32)  sServer->GetMaxLate() );
    print_status(statusFile, stdOut,"%11s", numStr);

    ::qtss_snprintf(numStr, sizeof(numStr) -1, "%s", "0");
    if (deltaPackets > 0)
        qtss_snprintf(numStr, sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) ((SInt64) deltaQuality /  (SInt64) deltaPackets));
    print_status(statusFile, stdOut,"%11s", numStr);

    qtss_snprintf(numStr,sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) sServer->GetNumThinned() );
    print_status(statusFile, stdOut,"%11s", numStr);

    
    
    char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
    (void) QTSSRollingLog::FormatDate(theDateBuffer, false);
    
    qtss_snprintf(dateStr,sizeof(dateStr) -1, "%s", theDateBuffer );
    print_status(statusFile, stdOut,"%24s\n", dateStr);
}
Esempio n. 22
0
void SendStats(QTSS_StreamRef inStream, UInt32  refreshInterval, Bool16 displayHelp, StrPtrLen* fieldList)
{
    struct FieldIndex {
        char*   fieldName;
        int fieldIndex;
    };
    
    const FieldIndex kFieldIndexes[] = {
                                    {"title", 1},
                                    {"dnsname", 2},
                                    {"curtime", 3},
                                    {"", 4},
                                    {"serververs", 5},
                                    {"serverbornon", 6},
                                    {"serverstatus", 7},
                                    {"", 8},
                                    {"", 9},
                                    {"", 10},
                                    {"", 11},
                                    {"", 12},
                                    {"", 13},
                                    {"currtp", 14},
                                    {"currtsp", 15},
                                    {"currtsphttp", 16},
                                    {"curthru", 17},
                                    {"curpkts", 18},
                                    {"totbytes", 19},
                                    {"totconns", 20},
                                    {"", 21},
                                    {"connlimit", 22},
                                    {"thrulimit", 23},
                                    {"moviedir", 24},
                                    {"rtspip", 25},
                                    {"rtspport", 26},
                                    {"rtsptimeout", 27},
                                    {"rtptimeout", 28},
                                    {"secstobuffer", 29},
                                    {"", 30},
                                    {"accesslog", 31},
                                    {"accesslogdir",32},
                                    {"accesslogname", 33},
                                    {"accessrollsize", 34},
                                    {"accessrollinterval", 35},
                                    {"", 36},
                                    {"errorlog", 37},
                                    {"errorlogdir", 38},
                                    {"errorlogname", 39},
                                    {"errorrollsize", 40},
                                    {"errorrollinterval", 41},
                                    {"errorloglevel", 42},
                                    {"", 43},
                                    {"assertbreak", 44},
                                    {"autostart", 45},
                                    {"totbytesupdateinterval", 46},
                                    {"reflectordelay", 47},
                                    {"reflectorbucketsize", 48},
                                    {"historyinterval", 49},
                                    {"outoffiledesc", 50},
                                    {"numudpsockets", 51},
                                    {"apiversion", 52},
                                    {"numreliableudpbuffers", 53},
                                    {"reliableudpwastedbytes", 54},
                                    {"numtaskthreads", 55}
    };
    const int kMaxFieldNum = 55;
    static char* kEmptyStr = "?";
    char* thePrefStr = kEmptyStr;

    char buffer[1024];

    (void)QTSS_Write(inStream, sResponseHeader, ::strlen(sResponseHeader), NULL, 0);

    if (refreshInterval > 0)
    {
        qtss_sprintf(buffer, "<META HTTP-EQUIV=Refresh CONTENT=%"_U32BITARG_">\n", refreshInterval);
        (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
    }
        
    //qtss_sprintf(buffer, "<body text=\"#000000\" bgcolor=\"#C0C0C0\" link=\"#0000FF\" vlink=\"#551A8B\" alink=\"#0000FF\">\n");
    //(void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
    
    char *theHTML =  "<HTML><BODY>\n";
    
    (void)QTSS_Write(inStream, theHTML, ::strlen(theHTML), NULL, 0);
    
    if (displayHelp)
    {
    
    #ifndef __MacOSX__
        static StrPtrLen sHelpLine1("<P><b>Streaming Server Statistics Help</b></P>\n");
    #else
        static StrPtrLen sHelpLine1("<P><b>QuickTime Streaming Server Statistics Help</b></P>\n");
    #endif

        static StrPtrLen sHelpLine2("<P>Example:</P>\n");
        static StrPtrLen sHelpLine3("<BLOCKQUOTE><P>http://server/statsURL?help&amp;refresh=15&amp;fields=curtime,cpuload </P>\n");

        static StrPtrLen sHelpLine4("\"?\" means that there are options being attached to the stats request.<BR>\n");
        static StrPtrLen sHelpLine5("\"&amp;\" separates multiple stats options<BR>\n<BR>\n");

        static StrPtrLen sHelpLine6("<P>The three possible parameters to stats are:</P>\n");
        static StrPtrLen sHelpLine7("<P>\"help\"  -- shows the help information you're reading right now.</P>\n");
        static StrPtrLen sHelpLine8("<P>\"refresh=&#91;n&#93;\"  -- tells the browser to automatically update the page every &#91;n&#93; seconds.</P>\n");
        static StrPtrLen sHelpLine9("<P>\"fields=&#91;fieldList&#93;\"  -- show only the fields specified in comma delimited &#91;fieldList&#93;</P>\n");
        static StrPtrLen sHelpLine10("<BLOCKQUOTE>The following fields are available for use with the \"fields\" option:</P><BLOCKQUOTE><DL>\n");
        
        (void)QTSS_Write(inStream, sHelpLine1.Ptr, sHelpLine1.Len, NULL, 0);
        (void)QTSS_Write(inStream, sHelpLine2.Ptr, sHelpLine2.Len, NULL, 0);
        (void)QTSS_Write(inStream, sHelpLine3.Ptr, sHelpLine3.Len, NULL, 0);

        (void)QTSS_Write(inStream, sHelpLine4.Ptr, sHelpLine4.Len, NULL, 0);
        (void)QTSS_Write(inStream, sHelpLine5.Ptr, sHelpLine5.Len, NULL, 0);

        (void)QTSS_Write(inStream, sHelpLine6.Ptr, sHelpLine6.Len, NULL, 0);
        (void)QTSS_Write(inStream, sHelpLine7.Ptr, sHelpLine7.Len, NULL, 0);
        (void)QTSS_Write(inStream, sHelpLine8.Ptr, sHelpLine8.Len, NULL, 0);
        (void)QTSS_Write(inStream, sHelpLine9.Ptr, sHelpLine9.Len, NULL, 0);
        (void)QTSS_Write(inStream, sHelpLine10.Ptr, sHelpLine10.Len, NULL, 0);      
    
        for (short i = 0; i < kMaxFieldNum; i++)
        {
                qtss_sprintf(buffer, "<DT><I>%s</I></DT>\n", kFieldIndexes[i].fieldName);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
        }
        
        static StrPtrLen sHelpLine11("</DL></BLOCKQUOTE></BLOCKQUOTE></BLOCKQUOTE><BR><P><HR>");
        (void)QTSS_Write(inStream, sHelpLine11.Ptr, sHelpLine11.Len, NULL, 0);      
    }

    StringParser fieldNamesParser(fieldList);
    StrPtrLen fieldName;
    int fieldNum = 0;
    do
    {
    
            
        if (fieldList != NULL)
        {
            fieldNum = 0;
            
            fieldNamesParser.ConsumeWord(&fieldName);
            
            for (short i = 0; i < kMaxFieldNum; i++)
            {
                if ( fieldName.Equal(StrPtrLen(kFieldIndexes[i].fieldName, ::strlen(kFieldIndexes[i].fieldName))) )
                {
                    fieldNum = kFieldIndexes[i].fieldIndex;
                    break;
                }
            }
        }
        else
        {
            fieldNum++;
            if ( fieldNum > kMaxFieldNum )
                fieldNum = 0;
        }

        UInt32 theLen = 0;
        
        switch (fieldNum)
        {
            case 1:
            {
#if __MacOSX__
                    static StrPtrLen sStatsLine1("<TITLE>QuickTime Streaming Server Stats</TITLE><BR>\n");
                    (void)QTSS_Write(inStream, sStatsLine1.Ptr, sStatsLine1.Len, NULL, 0);      
#else
                    static StrPtrLen sStatsLine1("<TITLE>Streaming Server Stats</TITLE><BR>\n");
                    (void)QTSS_Write(inStream, sStatsLine1.Ptr, sStatsLine1.Len, NULL, 0);      
#endif
                    
#if __MacOSX__
                    static StrPtrLen sStatsLine2("<center><h1>QuickTime Streaming Server Statistics</h1></center>\n");
                    (void)QTSS_Write(inStream, sStatsLine2.Ptr, sStatsLine2.Len, NULL, 0);      
#else
                    static StrPtrLen sStatsLine2("<center><h1>Streaming Server Statistics</h1></center>\n");
                    (void)QTSS_Write(inStream, sStatsLine2.Ptr, sStatsLine2.Len, NULL, 0);      
#endif
            }
            break;
        
            case 2:
            {
                StrPtrLen theDNS;
                (void)QTSS_GetValuePtr(sServer, qtssSvrDefaultDNSName, 0, (void**)&theDNS.Ptr, &theDNS.Len);
                
                if ( theDNS.Ptr == NULL )
                {   // no DNS, try for the IP address only.
                    (void)QTSS_GetValuePtr(sServer, qtssSvrDefaultIPAddr, 0, (void**)&theDNS.Ptr, &theDNS.Len);
                    
                }
                
                if ( theDNS.Ptr != NULL )
                {
                    qtss_sprintf(buffer, "<b>DNS Name (default): </b> %s<BR>\n", theDNS.Ptr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
            
            case 3:
            {
                char uptimebuffer[1024];
                time_t curTime = ::time(NULL); 
                qtss_sprintf(uptimebuffer, "<b>Current Time: </b> %s<BR>\n", qtss_ctime(&curTime, buffer, sizeof(buffer)));
                (void)QTSS_Write(inStream, uptimebuffer, ::strlen(uptimebuffer), NULL, 0);    
                
                time_t upTime = curTime - sStartupTime;
                #define kDaySeconds  (24 * 60 * 60)
                #define kHourSeconds  (60 * 60)
                #define kMinuteSeconds 60

                UInt32 upTimeDays = upTime / kDaySeconds;
                UInt32 upTimeHours = (upTime % kDaySeconds) / kHourSeconds;
                UInt32 upTimeMinutes = (upTime % kHourSeconds) / kMinuteSeconds;
                UInt32 upTimeSeconds = (upTime % kMinuteSeconds);
                qtss_snprintf(uptimebuffer,sizeof(uptimebuffer), "<b>Up Time Total Seconds: </b> %"_U32BITARG_"<BR>\n", upTime);
                uptimebuffer[sizeof(uptimebuffer) -1] = 0;
                (void)QTSS_Write(inStream, uptimebuffer, ::strlen(uptimebuffer), NULL, 0);    
                       
                qtss_snprintf(uptimebuffer,sizeof(uptimebuffer), "<b>Up Time: </b> %"_U32BITARG_" days %"_U32BITARG_" hours %"_U32BITARG_" minutes %"_U32BITARG_" seconds <BR>\n", upTimeDays, upTimeHours,upTimeMinutes, upTimeSeconds);
                uptimebuffer[sizeof(uptimebuffer) -1] = 0;
                (void)QTSS_Write(inStream, uptimebuffer, ::strlen(uptimebuffer), NULL, 0);    
            }
            break;
            
            case 4:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
    
            case 5:
            {
                StrPtrLen theVersion;
                (void)QTSS_GetValuePtr(sServer, qtssSvrRTSPServerHeader, 0, (void**)&theVersion.Ptr, &theVersion.Len);
                Assert(theVersion.Ptr != NULL);
                if (theVersion.Len > 7) //Skip the "Server:" text
                   theVersion.Ptr += 7;
                qtss_sprintf(buffer, "<b>Server Version: </b>%s<BR>\n", theVersion.Ptr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 6:
            {
                StrPtrLen theBuildDate;
                (void)QTSS_GetValuePtr(sServer, qtssSvrServerBuildDate, 0, (void**)&theBuildDate.Ptr, &theBuildDate.Len);
                Assert(theBuildDate.Ptr != NULL);
                qtss_sprintf(buffer, "<b>Server Build Date: </b> %s<BR>\n", theBuildDate.Ptr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 7:
            {
                char statusBuffer[1024];
                const char* states[]    = { "Starting Up",
                                            "Running",
                                            "Refusing Connections",
                                            "Fatal Error",
                                            "Shutting Down"
                                          };
                QTSS_ServerState theState = qtssRunningState;
                theLen = sizeof(theState);
                (void)QTSS_GetValue(sServer, qtssSvrState, 0, &theState, &theLen);

                if (theState == qtssRunningState)
                {	qtss_snprintf(statusBuffer, sizeof(statusBuffer), "<b>Status: </b> %s since %s<BR>", states[theState], qtss_ctime(&sStartupTime,buffer,sizeof(buffer)));
                }
                else
                    qtss_snprintf(statusBuffer,sizeof(statusBuffer), "<b>Status: </b> %s<BR>", states[theState]);
                (void)QTSS_Write(inStream, statusBuffer, ::strlen(statusBuffer), NULL, 0);      
            }
            break;
            
            case 8:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
    
            case 9:
            {
                
                //NOOP
            }
            break;
            
            case 10:
            {
                
                //NOOP
            }
            break;
    
            case 11:
            {
                
                //NOOP
            }
            break;
    
            case 12:
            {       
            /*  
                struct vm_statistics vmStats = {};
                if (vm_statistics (current_task (), &vmStats) != KERN_SUCCESS)
                    memset (&stats, '\0', sizeof (vmStats)) ;
            */
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
            
            case 13:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
                
            //**********************************



    
            case 14:
            {
                (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurConn, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Current RTP Connections: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 15:
            {
                (void)QTSS_GetValueAsString(sServer, qtssRTSPCurrentSessionCount, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Current RTSP Connections: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 16:
            {
                (void)QTSS_GetValueAsString(sServer, qtssRTSPHTTPCurrentSessionCount, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Current RTSP over HTTP Connections: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 17:
            {
                UInt32 curBandwidth = 0;
                theLen = sizeof(curBandwidth);
                (void)QTSS_GetValue(sServer, qtssRTPSvrCurBandwidth, 0, &curBandwidth, &theLen);

                qtss_sprintf(buffer, "<b>Current Throughput: </b> %"_U32BITARG_" kbits<BR>\n", curBandwidth/1024);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 18:
            {
                (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurPackets, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Current Packets Per Second: </b> %s <BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 19:
            {
                (void)QTSS_GetValueAsString(sServer, qtssRTPSvrTotalBytes, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Total Bytes Served: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 20:
            {
                (void)QTSS_GetValueAsString(sServer, qtssRTPSvrTotalConn, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Total Connections: </b> %s<BR>", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
            
            case 21:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
    
            //**************************************
            case 22:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMaximumConnections, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Maximum Connections: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 23:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMaximumBandwidth, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Maximum Throughput: </b> %s Kbits<BR>\n",thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 24:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMovieFolder, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Movie Folder Path: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 25:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsRTSPIPAddr, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>RTSP IP Address: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);
            }
            break;
    
            case 26:
            {
                static StrPtrLen sRTSPPortsStart("<b>RTSP Ports: </b> ");
                (void)QTSS_Write(inStream, sRTSPPortsStart.Ptr, sRTSPPortsStart.Len, NULL, 0);      

                StrPtrLen thePort;
                for (UInt32 theIndex = 0; true; theIndex++)
                {
                    QTSS_Error theErr = QTSS_GetValuePtr(sServer, qtssSvrRTSPPorts, theIndex, (void**)&thePort.Ptr, &thePort.Len);
                    if (theErr != QTSS_NoErr)
                        break;

                    Assert(thePort.Ptr != NULL);
                    char temp[20];
                    qtss_sprintf(temp, "%u ", *(UInt16*)thePort.Ptr);
                    (void)QTSS_Write(inStream, temp, ::strlen(temp), NULL, 0);      
                }
                
                static StrPtrLen sRTSPPortsEnd("<BR>\n");
                (void)QTSS_Write(inStream, sRTSPPortsEnd.Ptr, sRTSPPortsEnd.Len, NULL, 0);      
            }
            break;
    
            case 27:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsRTSPTimeout, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>RTP Timeout: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 28:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsRTPTimeout, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>RTP Timeout: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 29:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
    
            case 30:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
    
            case 31:
            {
                if ( sAccessLogPrefs  != NULL )
                {
                    thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logging");
                    qtss_sprintf(buffer, "<b>Access Logging: </b> %s<BR>\n", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
    
            case 32:
            {
                if ( sAccessLogPrefs  != NULL )
                {
                    thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_dir");
                    qtss_sprintf(buffer, "<b>Access Log Directory: </b> %s<BR>\n", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
    
            case 33:
            {
                if ( sAccessLogPrefs  != NULL )
                {
                    thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_name");
                    qtss_sprintf(buffer, "<b>Access Log Name: </b> %s<BR>\n", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
    
            case 34:
            {
                if ( sAccessLogPrefs  != NULL )
                {
                    thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_size");
                    qtss_sprintf(buffer, "<b>Access Log Roll Size: </b> %s<BR>\n", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
    
            case 35:
            {
                if ( sAccessLogPrefs  != NULL )
                {
                    thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_interval");
                    qtss_sprintf(buffer, "<b>Access Log Roll Interval (days): </b> %s<BR>", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
            
            case 36:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
    
            case 37:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogEnabled, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Error Logging: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 38:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogDir, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Error Log Directory: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 39:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogName, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Error Log Name: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 40:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMaxErrorLogSize, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Error Log Roll Size: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 41:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorRollInterval, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Error Log Roll Interval (days): </b> %s<BR>\n",thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 42:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogVerbosity, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Error Log Verbosity: </b> %s<BR>", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
            
            case 43:
            {
                (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0);        
            }
            break;
    
            case 44:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsBreakOnAssert, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Break On Assert: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 45:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsAutoRestart, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>AutoStart: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 46:
            {
                (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsTotalBytesUpdate, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Total Bytes Update Interval: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 47:
            {
                if (sReflectorPrefs != NULL)
                {
                    thePrefStr = GetPrefAsString(sReflectorPrefs, "reflector_delay");
                    qtss_sprintf(buffer, "<b>Reflector Delay Time: </b> %s<BR>\n", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
    
            case 48:
            {
                if (sReflectorPrefs != NULL)
                {
                    thePrefStr = GetPrefAsString(sReflectorPrefs, "reflector_bucket_size");
                    qtss_sprintf(buffer, "<b>Reflector Bucket Size: </b> %s<BR>\n", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }
            }
            break;
    
            case 49:
            {
                if ( sSvrControlPrefs != NULL)
                {
                    thePrefStr = GetPrefAsString(sSvrControlPrefs, "history_update_interval");
                    qtss_sprintf(buffer, "<b>History Update Interval: </b> %s<BR>\n", thePrefStr);
                    (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
                }       
            }
            break;
    
            case 50:
            {
                Bool16 isOutOfDescriptors = false;
                theLen = sizeof(isOutOfDescriptors);
                (void)QTSS_GetValue(sServer, qtssSvrIsOutOfDescriptors, 0, &isOutOfDescriptors, &theLen);

                qtss_sprintf(buffer, "<b>Out of file descriptors: </b> %d<BR>\n", isOutOfDescriptors);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 51:
            {
                (void)QTSS_GetValueAsString(sServer, qtssRTPSvrNumUDPSockets, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Number of UDP sockets: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
    
            case 52:
            {
                UInt32 apiVersion = 0;
                UInt32 size = sizeof(UInt32);
                (void)QTSS_GetValue(sServer, qtssServerAPIVersion, 0, &apiVersion, &size);
                qtss_sprintf(buffer, "<b>API version: </b> %d.%d<BR>\n", (int)( (UInt32) (apiVersion & (UInt32) 0xFFFF0000L) >> 16), (int)(apiVersion &(UInt32) 0x0000FFFFL));
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;

            case 53:
            {
                UInt32 reliableUDPBuffers = 0;
                UInt32 blahSize = sizeof(reliableUDPBuffers);
                (void)QTSS_GetValue(sServer, qtssSvrNumReliableUDPBuffers, 0, &reliableUDPBuffers, &blahSize);
                qtss_sprintf(buffer, "<b>Num Reliable UDP Retransmit Buffers: </b> %"_U32BITARG_"<BR>\n", reliableUDPBuffers);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;

            case 54:
            {
                UInt32 wastedBufSpace = 0;
                UInt32 blahSize2 = sizeof(wastedBufSpace);
                (void)QTSS_GetValue(sServer, qtssSvrReliableUDPWastageInBytes, 0, &wastedBufSpace, &blahSize2);
                qtss_sprintf(buffer, "<b>Amount of buffer space being wasted in UDP Retrans buffers: </b> %"_U32BITARG_"<BR>\n", wastedBufSpace);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
            
            case 55:
            {
                (void)QTSS_GetValueAsString(sServer, qtssSvrNumThreads, 0, &thePrefStr);
                qtss_sprintf(buffer, "<b>Number of Task Threads: </b> %s<BR>\n", thePrefStr);
                (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0);      
            }
            break;
             
            
    
            default:        
                break;
    
                
        } //switch fieldNum
            
            
        if (fieldList != NULL && !fieldNamesParser.Expect(','))
            fieldNum = 0;
            
        if (thePrefStr != kEmptyStr)
            delete [] thePrefStr; 
            
        thePrefStr = kEmptyStr;
            
    } while (fieldNum != 0);
    
    theHTML = "</BODY></HTML>\n";
    (void)QTSS_Write(inStream, theHTML, ::strlen(theHTML), NULL, 0);        
}
Esempio n. 23
0
bool XMLTag::ParseTag(StringParser* parser, DTDVerifier* verifier, char* errorBuffer, int errorBufferSize)
{
    while (true)
    {
        if (!parser->GetThru(NULL, '<'))
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer, errorBufferSize, "Couldn't find a valid tag");
            return false;   // couldn't find beginning of tag
        }
            
        char c = parser->PeekFast();
        if (c == '/')
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer, errorBufferSize, "End tag with no begin tag on line %d", parser->GetCurrentLineNumber());
            return false;   // we shouldn't be seeing a close tag here
        }
            
        if ((c != '!') && (c != '?'))
            break;  // this should be the beginning of a regular tag
            
        ConsumeIfComment(parser);
        // otherwise this is a processing instruction or a c-data, so look for the next tag
    }
    
    int tagStartLine = parser->GetCurrentLineNumber();
    
    StrPtrLen temp;
    parser->ConsumeUntil(&temp, sNonNameMask);
    if (temp.Len == 0)
    {
        if (errorBuffer != NULL)
        {
            if (parser->GetDataRemaining() == 0)
                qtss_snprintf(errorBuffer, errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber());
            else
                qtss_snprintf(errorBuffer,  errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber());
        }
        return false;   // bad file
    }
        
    fTag = temp.GetAsCString();
    
    parser->ConsumeWhitespace();
    while ((parser->PeekFast() != '>') && (parser->PeekFast() != '/'))
    {
        // we must have an attribute value for this tag
        XMLAttribute* attr = new XMLAttribute;
        fAttributes.EnQueue(&attr->fElem);
        parser->ConsumeUntil(&temp, sNonNameMask);
        if (temp.Len == 0)
        {
            if (errorBuffer != NULL)
            {
                if (parser->GetDataRemaining() == 0)
                    qtss_snprintf(errorBuffer,  errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber());
                else
                    qtss_snprintf(errorBuffer,  errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber());
            }
            return false;   // bad file
        }

        attr->fAttrName = temp.GetAsCString();

        if (!parser->Expect('='))
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer,  errorBufferSize,"Missing '=' after attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
            return false;   // bad attribute specification
        }
        if (!parser->Expect('"'))
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer,  errorBufferSize,"Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
            return false;   // bad attribute specification
        }
            
        parser->ConsumeUntil(&temp, '"');
        attr->fAttrValue = temp.GetAsCString();
        if (!parser->Expect('"'))
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
            return false;   // bad attribute specification
        }
        
        if (verifier && !verifier->IsValidAttributeName(fTag, attr->fAttrName))
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s not allowed in tag %s on line %d", attr->fAttrName, fTag, parser->GetCurrentLineNumber());
            return false;   // bad attribute specification
        }

        if (verifier && !verifier->IsValidAttributeValue(fTag, attr->fAttrName, attr->fAttrValue))
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer,  errorBufferSize,"Bad value for attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber());
            return false;   // bad attribute specification
        }

        parser->ConsumeWhitespace();
    }
    
    if (parser->PeekFast() == '/')
    {
        // this is an empty element tag, i.e. no contents or end tag (e.g <TAG attr="value" />
        parser->Expect('/');
        if (!parser->Expect('>'))
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer,  errorBufferSize,"'>' must follow '/' on line %d", parser->GetCurrentLineNumber());
            return false;   // bad attribute specification
        }
        
        return true;    // we're done with this tag
    }
    
    if (!parser->Expect('>'))
    {
        if (errorBuffer != NULL)
            qtss_snprintf(errorBuffer,  errorBufferSize,"Bad format for tag <%s> on line %d", fTag, parser->GetCurrentLineNumber());
        return false;   // bad attribute specification
    }
    
    while(true)
    {
        parser->ConsumeUntil(&temp, '<');   // this is either value or whitespace
        if (parser->GetDataRemaining() < 4)
        {
            if (errorBuffer != NULL)
                qtss_snprintf(errorBuffer, errorBufferSize, "Reached end of file without end for tag <%s> declared on line %d", fTag, tagStartLine);
            return false;
        }
        if ((*parser)[1] == '/')
        {
            // we'll only assign a value if there were no embedded tags
            if (fEmbeddedTags.GetLength() == 0 && (!verifier || verifier->CanHaveValue(fTag)))
                fValue = temp.GetAsCString();
            else
            {
                // otherwise this needs to have been just whitespace
                StringParser tempParser(&temp);
                tempParser.ConsumeWhitespace();
                if (tempParser.GetDataRemaining() > 0)
                {
                    if (errorBuffer)
                    {
                        if (fEmbeddedTags.GetLength() > 0)
                            qtss_snprintf(errorBuffer,  errorBufferSize,"Unexpected text outside of tag on line %d", tagStartLine);
                        else
                            qtss_snprintf(errorBuffer, errorBufferSize, "Tag <%s> on line %d not allowed to have data", fTag, tagStartLine);
                    }
                }
            }
            break;  // we're all done with this tag
        }
        
        if (((*parser)[1] != '!') && ((*parser)[1] != '?'))
        {
            // this must be the beginning of an embedded tag
            XMLTag* tag = NEW XMLTag();
            fEmbeddedTags.EnQueue(&tag->fElem);
            if (!tag->ParseTag(parser, verifier, errorBuffer, errorBufferSize))
                return false;
                
            if (verifier && !verifier->IsValidSubtag(fTag, tag->GetTagName()))
            {
                if (errorBuffer != NULL)
                    qtss_snprintf(errorBuffer, errorBufferSize, "Tag %s not allowed in tag %s on line %d", tag->GetTagName(), fTag, parser->GetCurrentLineNumber());
                return false;   // bad attribute specification
            }
        }
        else
        {
            parser->ConsumeLength(NULL, 1); // skip '<'
            ConsumeIfComment(parser);
        }
    }

    parser->ConsumeLength(NULL, 2); // skip '</'
    parser->ConsumeUntil(&temp, sNonNameMask);
    if (!temp.Equal(fTag))
    {
        char* newTag = temp.GetAsCString();
        if (errorBuffer != NULL)
            qtss_snprintf(errorBuffer,  errorBufferSize,"End tag </%s> on line %d doesn't match tag <%s> declared on line %d", newTag, parser->GetCurrentLineNumber(),fTag, tagStartLine);
        delete newTag;
        return false;   // bad attribute specification
    }
    
    if (!parser->GetThru(NULL, '>'))
    {
        if (errorBuffer != NULL)
            qtss_snprintf(errorBuffer,  errorBufferSize,"Couldn't find end of tag <%s> declared on line %d", fTag, tagStartLine);
        return false;   // bad attribute specification
    }
    
    return true;
}
Esempio n. 24
0
QTSS_Error	QTSSModuleUtils::SendHTTPErrorResponse( QTSS_RTSPRequestObject inRequest,
													QTSS_SessionStatusCode inStatusCode,
                                                    Bool16 inKillSession,
                                                    char *errorMessage)
{
    static Bool16 sFalse = false;
    
    //set status code for access log
    (void)QTSS_SetValue(inRequest, qtssRTSPReqStatusCode, 0, &inStatusCode, sizeof(inStatusCode));

    if (inKillSession) // tell the server to end the session
        (void)QTSS_SetValue(inRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse));
    
    ResizeableStringFormatter theErrorMessage(NULL, 0); //allocates and deletes memory
    ResizeableStringFormatter bodyMessage(NULL,0); //allocates and deletes memory

    char messageLineBuffer[64]; // used for each line
    static const int maxMessageBufferChars = sizeof(messageLineBuffer) -1;
    messageLineBuffer[maxMessageBufferChars] = 0; // guarantee termination

    // ToDo: put in a more meaningful http error message for each error. Not required by spec.
    // ToDo: maybe use the HTTP protcol class static error strings.
    char* errorMsg = "error"; 

    DateBuffer theDate;
    DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time

    UInt32 realCode = 0;
    UInt32 len = sizeof(realCode);
    (void) QTSS_GetValue(inRequest, qtssRTSPReqRealStatusCode, 0,  (void*)&realCode,&len);

    char serverHeaderBuffer[64]; // the qtss Server: header field
    len = sizeof(serverHeaderBuffer) -1; // leave room for terminator
    (void) QTSS_GetValue(sServer, qtssSvrRTSPServerHeader, 0,  (void*)serverHeaderBuffer,&len);
    serverHeaderBuffer[len] = 0; // terminate.
 
    qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "HTTP/1.1 %"_U32BITARG_" %s",realCode, errorMsg);
    theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));
    theErrorMessage.PutEOL();

    theErrorMessage.Put(serverHeaderBuffer,::strlen(serverHeaderBuffer));
    theErrorMessage.PutEOL();
 
    qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "Date: %s",theDate.GetDateBuffer());
    theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));
    theErrorMessage.PutEOL();
 
    Bool16 addBody =  (errorMessage != NULL && ::strlen(errorMessage) != 0); // body error message so add body headers
    if (addBody) // body error message so add body headers
    {
        // first create the html body
        static const StrPtrLen htmlBodyStart("<html><body>\n");
        bodyMessage.Put(htmlBodyStart.Ptr,htmlBodyStart.Len);
 
        //<h1>errorMessage</h1>\n
        static const StrPtrLen hStart("<h1>");
        bodyMessage.Put(hStart.Ptr,hStart.Len);

        bodyMessage.Put(errorMessage,::strlen(errorMessage));

        static const StrPtrLen hTerm("</h1>\n");
        bodyMessage.Put(hTerm.Ptr,hTerm.Len);
 
        static const StrPtrLen htmlBodyTerm("</body></html>\n");
        bodyMessage.Put(htmlBodyTerm.Ptr,htmlBodyTerm.Len);

        // write body headers
        static const StrPtrLen bodyHeaderType("Content-Type: text/html");
        theErrorMessage.Put(bodyHeaderType.Ptr,bodyHeaderType.Len);
        theErrorMessage.PutEOL();

        qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "Content-Length: %"_U32BITARG_"", bodyMessage.GetBytesWritten());
        theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));        
        theErrorMessage.PutEOL();
    }

    static const StrPtrLen headerClose("Connection: close");
    theErrorMessage.Put(headerClose.Ptr,headerClose.Len);
    theErrorMessage.PutEOL();

    theErrorMessage.PutEOL();  // terminate headers with empty line

    if (addBody) // add html body
    {
        theErrorMessage.Put(bodyMessage.GetBufPtr(),bodyMessage.GetBytesWritten());
    }

    //
    // Now that we've formatted the message into the temporary buffer,
    // write it out to the request stream and the Client Session object
    (void)QTSS_Write(inRequest, theErrorMessage.GetBufPtr(), theErrorMessage.GetBytesWritten(), NULL, 0);
    (void)QTSS_SetValue(inRequest, qtssRTSPReqRespMsg, 0, theErrorMessage.GetBufPtr(), theErrorMessage.GetBytesWritten());
    
    return QTSS_RequestFailed;
}
Esempio n. 25
0
QTSS_Error LogError(QTSS_RoleParamPtr inParamBlock)
{
    Assert(NULL != inParamBlock->errorParams.inBuffer);
    if (inParamBlock->errorParams.inBuffer == NULL)
        return QTSS_NoErr;
        
    UInt16 verbLvl = (UInt16) inParamBlock->errorParams.inVerbosity;
    if (verbLvl >= qtssIllegalVerbosity)
    	verbLvl = qtssFatalVerbosity;
        
    QTSServerPrefs* thePrefs = QTSServerInterface::GetServer()->GetPrefs();
        
    OSMutexLocker locker(sLogMutex);
    if (thePrefs->GetErrorLogVerbosity() >= inParamBlock->errorParams.inVerbosity)
    {
         size_t inStringLen = ::strlen(inParamBlock->errorParams.inBuffer);
         size_t lastStringLen = ::strlen(sLastErrorString); 
         Bool16 isDuplicate = true;
         
         if (inStringLen > sizeof(sLastErrorString) -1) //truncate to max char buffer subtract \0 terminator
            inStringLen = sizeof(sLastErrorString) -1;
            
         if (lastStringLen != inStringLen) //same size?
            isDuplicate = false; // different sizes
         else if (::strncmp(inParamBlock->errorParams.inBuffer, sLastErrorString, lastStringLen ) != 0 ) //same chars?
            isDuplicate = false; //different  chars
            
        //is this error message the same as the last one we received?       
        if ( isDuplicate )
        {   //yes?  increment count and bail if it's not the first time we've seen this message (otherwise fall thourhg and write it to the log)
            sDupErrorStringCount++;
            return QTSS_NoErr;
        }
        else 
        {
            //we have a new error message, write a "previous line" message before writing the new log entry
            if ( sDupErrorStringCount >= 1 )
            {
            /***  clean this up - lots of duplicate code ***/
            
                //The error logger is the bottleneck for any and all messages printed by the server.
                //For debugging purposes, these messages can be printed to stdout as well.
                if (thePrefs->IsScreenLoggingEnabled())
                    qtss_printf("--last message repeated %d times\n", sDupErrorStringCount);
            
                CheckErrorLogState();
                
                if (sErrorLog == NULL)
                    return QTSS_NoErr;
                    
                //timestamp the error
                char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
                Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
                //for now, just ignore the error.
                if (!result)
                    theDateBuffer[0] = '\0';
        
                char tempBuffer[kMaxLogStringLen];
                qtss_snprintf(tempBuffer,sizeof(tempBuffer), "%s: --last message repeated %d times\n", theDateBuffer, sDupErrorStringCount);
                
                sErrorLog->WriteToLog(tempBuffer, kAllowLogToRoll);
    
                sDupErrorStringCount = 0;
            }
            ::strncpy(sLastErrorString, inParamBlock->errorParams.inBuffer, sizeof(sLastErrorString));
            sLastErrorString[sizeof(sLastErrorString)-1] = '\0';
        
        }

        //The error logger is the bottleneck for any and all messages printed by the server.
        //For debugging purposes, these messages can be printed to stdout as well.
        if (thePrefs->IsScreenLoggingEnabled())
            qtss_printf("%s %s\n", sErrorLevel[verbLvl], inParamBlock->errorParams.inBuffer);
        
        CheckErrorLogState();
        
        if (sErrorLog == NULL)
            return QTSS_NoErr;
            
        //timestamp the error
        char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
        Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
        //for now, just ignore the error.
        if (!result)
            theDateBuffer[0] = '\0';

        char tempBuffer[kMaxLogStringLen];
        qtss_snprintf(tempBuffer,sizeof(tempBuffer), "%s: %s %s\n", theDateBuffer, sErrorLevel[verbLvl], inParamBlock->errorParams.inBuffer);
        tempBuffer[sizeof(tempBuffer)-2] = '\n'; //make sure the entry has a line feed before the \0 terminator
        tempBuffer[sizeof(tempBuffer)-1] = '\0'; //make sure it is 0 terminated.
        
        sErrorLog->WriteToLog(tempBuffer, kAllowLogToRoll);
    }
    return QTSS_NoErr;
}
Esempio n. 26
0
Bool16 PLBroadcastDef::SetDefaults( const char* setupFileName )
{
    Bool16  didFail = false;
    
    if (mDestAddress != NULL)
        mIgnoreFileIP = true;
        
    if ( !didFail && !mIgnoreFileIP)    
        didFail = this->SetValue( &mDestAddress, SocketUtils::GetIPAddrStr(0)->Ptr );

    if ( !didFail ) 
        didFail = this->SetValue( &mBasePort, "5004" );

    if ( !didFail ) 
        didFail = this->SetValue( &mPlayMode, "sequential_looped" );
    
    if ( !didFail ) 
        didFail = this->SetValue( &mMaxUpcomingMovieListSize, "7" );
    
    if ( !didFail ) 
        didFail = this->SetValue( &mLogging, "enabled" );

    if ( !didFail ) 
        didFail = this->SetValue( &mRTSPPort, "554" );

    char    nameBuff[512];
    ::strcpy( nameBuff, "broadcast" );
    if (setupFileName)
        ::strcpy( nameBuff, setupFileName );
        
    int     baseLen = strlen(nameBuff);

/*
    
    if you want to add .log to the base name of the 
    description file with the .ext stripped, un comment 
    this code.
    rt 8.12.99
*/
    char    *ext = NULL;
    ext = ::strrchr( nameBuff, '.' );
    if ( ext )
    {   
        *ext  = 0;
        baseLen = ::strlen(nameBuff);
    }

        
    ::strcat( nameBuff, ".log" );   
    if ( !didFail )
        didFail = this->SetValue( &mLogFile, nameBuff );

    nameBuff[baseLen] = 0;  
    ::strcat( nameBuff, ".ply" );   
    if ( !didFail ) 
        didFail = this->SetValue( &mPlayListFile, nameBuff );
    

//  nameBuff[baseLen] = 0;
//  ::strcat( nameBuff, ".mov" );   
//  if ( !didFail ) 
//      didFail = this->SetValue( &mSDPReferenceMovie, nameBuff );
    
    nameBuff[baseLen] = 0;
    ::strcat( nameBuff, ".sdp" );
    if ( !didFail ) 
        didFail = this->SetValue( &mSDPFile, nameBuff );

    if ( !didFail ) 
        didFail = this->SetValue( &mDestSDPFile, "no_name" );
    

/* current, upcoming, and replacelist created by [email protected] */
    nameBuff[baseLen] = 0;
    ::strcat( nameBuff, ".current" );   
    if ( !didFail )
        didFail = this->SetValue( &mCurrentFile, nameBuff );

    nameBuff[baseLen] = 0;
    ::strcat( nameBuff, ".upcoming" );  
    if ( !didFail )
        didFail = this->SetValue( &mUpcomingFile, nameBuff );

    nameBuff[baseLen] = 0;
    ::strcat( nameBuff, ".replacelist" );   
    if ( !didFail )
        didFail = this->SetValue( &mReplaceFile, nameBuff );

    nameBuff[baseLen] = 0;
    ::strcat( nameBuff, ".stoplist" );  
    if ( !didFail )
        didFail = this->SetValue( &mStopFile, nameBuff );
        
    nameBuff[baseLen] = 0;
    ::strcat( nameBuff, ".insertlist" );    
    if ( !didFail )
        didFail = this->SetValue( &mInsertFile, nameBuff );
    
    if ( !didFail ) 
        didFail = this->SetValue( &mShowCurrent, "enabled" );
        
    if ( !didFail ) 
        didFail = this->SetValue( &mShowUpcoming, "enabled" );
        
    if ( !didFail ) 
        didFail = this->SetValue( &mStartTime, "0" );

    if ( !didFail ) 
        didFail = this->SetValue( &mEndTime, "0" );

    if ( !didFail ) 
        didFail = this->SetValue( &mIsDynamic, "disabled" );
        
    if ( !didFail ) 
        didFail = this->SetValue( &mName, "" );

    if ( !didFail ) 
        didFail = this->SetValue( &mPassword, "" );

    if ( !didFail ) 
        didFail = this->SetValue( &mTTL, "1" );

    if ( !didFail ) 
        didFail = this->SetValue( &mClientBufferDelay, "0" );
   
    //see if there is a defaults File.
    //if there is one load it and over-ride the other defaults
    if (NULL != setupFileName)
    {
       int len = ::strlen(setupFileName) + 10;
       char *defaultFileName = new char[len];
       qtss_snprintf(defaultFileName, len, "%s%s", setupFileName, ".def");
       (void) ::ParseConfigFile( false, defaultFileName, ConfigSetter, this ); //ignore if no defaults file
       delete [] defaultFileName;
    }
 
/* ***************************************************** */
    return didFail;
}
Esempio n. 27
0
/*!
	\brief 事件由ServiceSession Task进行处理,大多数为网络报文处理事件 
	\param 
	\return 处理完成返回0,断开Session返回-1
	\ingroup 
	\see 
*/
SInt64 CServiceSession::Run()
{
	//获取事件类型
    EventFlags events = this->GetEvents();
    QTSS_Error err = QTSS_NoErr;
    QTSSModule* theModule = NULL;
    UInt32 numModules = 0;
    // Some callbacks look for this struct in the thread object
    OSThreadDataSetter theSetter(&fModuleState, NULL);
        
    //超时事件或者Kill事件,进入释放流程:清理 & 返回-1
    if (events & Task::kKillEvent)
        fLiveSession = false;

	if(events & Task::kTimeoutEvent)
	{
		//客户端Session超时,暂时不处理 
		char msgStr[512];
		qtss_snprintf(msgStr, sizeof(msgStr), "session timeout,release session\n");
		QTSServerInterface::LogError(qtssMessageVerbosity, msgStr);
		return -1;
	}

	//正常事件处理流程
    while (this->IsLiveSession())
    {
        //报文处理以状态机的形式,可以方便多次处理同一个消息
        switch (fState)
        {
            case kReadingFirstRequest://首次对Socket进行读取
            {
                if ((err = fInputStream.ReadRequest()) == QTSS_NoErr)
                {
					//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
					//但,还不能构成一个整体报文,还要继续等待读取...
                    fInputSocketP->RequestEvent(EV_RE);
                    return 0;
                }
                
                if ((err != QTSS_RequestArrived) && (err != E2BIG))
                {
                    // Any other error implies that the client has gone away. At this point,
                    // we can't have 2 sockets, so we don't need to do the "half closed" check
                    // we do below
                    Assert(err > 0); 
                    Assert(!this->IsLiveSession());
                    break;
                }

                if ((err == QTSS_RequestArrived) || (err == E2BIG))
                    fState = kHaveCompleteMessage;
            }
            continue;            
            case kReadingRequest://读取请求报文
            {
				//读取锁,已经在处理一个报文包时,不进行新网络报文的读取和处理
                OSMutexLocker readMutexLocker(&fReadMutex);

				//网络请求报文存储在fInputStream中
                if ((err = fInputStream.ReadRequest()) == QTSS_NoErr)
                {
					//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
					//但,还不能构成一个整体报文,还要继续等待读取...
                    fInputSocketP->RequestEvent(EV_RE);
                    return 0;
                }
                
                if ((err != QTSS_RequestArrived) && (err != E2BIG) && (err != QTSS_BadArgument))
                {
                    //Any other error implies that the input connection has gone away.
                    // We should only kill the whole session if we aren't doing HTTP.
                    // (If we are doing HTTP, the POST connection can go away)
                    Assert(err > 0);
                    if (fOutputSocketP->IsConnected())
                    {
                        // If we've gotten here, this must be an HTTP session with
                        // a dead input connection. If that's the case, we should
                        // clean up immediately so as to not have an open socket
                        // needlessly lingering around, taking up space.
                        Assert(fOutputSocketP != fInputSocketP);
                        Assert(!fInputSocketP->IsConnected());
                        fInputSocketP->Cleanup();
                        return 0;
                    }
                    else
                    {
                        Assert(!this->IsLiveSession());
                        break;
                    }
                }
                fState = kHaveCompleteMessage;
            }
            case kHaveCompleteMessage://读取到完整的请求报文
            {
                Assert( fInputStream.GetRequestBuffer() );
                
                Assert(fRequest == NULL);
				//根据具体请求报文构造HTTPRequest请求类
				fRequest = NEW HTTPRequest(&sServiceStr, fInputStream.GetRequestBuffer());

				//在这里,我们已经读取了一个完整的Request,并准备进行请求的处理,直到响应报文发出
				//在此过程中,此Session的Socket不进行任何网络数据的读/写;
                fReadMutex.Lock();
                fSessionMutex.Lock();
                
                //清空发送缓冲区
                fOutputStream.ResetBytesWritten();
                
				//网络请求超过了缓冲区,返回Bad Request
                if (err == E2BIG)
                {
					//返回HTTP报文,错误码408
                    //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgRequestTooLong);
                    fState = kSendingResponse;
                    break;
                }
                // Check for a corrupt base64 error, return an error
                if (err == QTSS_BadArgument)
                {
					//返回HTTP报文,错误码408
                    //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64);
                    fState = kSendingResponse;
                    break;
                }

                Assert(err == QTSS_RequestArrived);
                fState = kFilteringRequest;
            }
            
            case kFilteringRequest:
            {
                //刷新Session保活时间
                fTimeoutTask.RefreshTimeout();

				//对请求报文进行解析
				QTSS_Error theErr = SetupRequest();
				//当SetupRequest步骤未读取到完整的网络报文,需要进行等待
				if(theErr == QTSS_WouldBlock)
				{
					this->ForceSameThread();
					fInputSocketP->RequestEvent(EV_RE);
					// We are holding mutexes, so we need to force
					// the same thread to be used for next Run()
                    return 0;//返回0表示有事件才进行通知,返回>0表示规定事件后调用Run

				}
                
                //每一步都检测响应报文是否已完成,完成则直接进行回复响应
                if (/*fRequest->HasResponseBeenSent()*/fOutputStream.GetBytesWritten() > 0)
                {
                    fState = kSendingResponse;
                    break;
                }

                fState = kPreprocessingRequest;
                break;
            }
                       
            case kPreprocessingRequest:
            {
                //请求预处理过程
				//TODO:报文处理过程
                fState = kCleaningUp;
				break;
            }

            case kProcessingRequest:
            {
                if (fOutputStream.GetBytesWritten() == 0)
                {
					//如果到这里,响应报文还没有形成,返回500 Server Internal Error
					////QTSSModuleUtils::SendErrorResponse(fRequest, qtssServerInternal, qtssMsgNoModuleForRequest);
                }

                fState = kSendingResponse;
            }
            case kSendingResponse:
            {
                //响应报文发送,确保完全发送
                Assert(fRequest != NULL);

				//发送响应报文
                err = fOutputStream.Flush();
                
                if (err == EAGAIN)
                {
                    // If we get this error, we are currently flow-controlled and should
                    // wait for the socket to become writeable again
					//如果收到Socket EAGAIN错误,那么我们需要等Socket再次可写的时候再调用发送
                    fSocket.RequestEvent(EV_WR);
                    this->ForceSameThread();
					// We are holding mutexes, so we need to force
					// the same thread to be used for next Run()
                    return 0;
                }
                else if (err != QTSS_NoErr)
                {
                    // Any other error means that the client has disconnected, right?
                    Assert(!this->IsLiveSession());
                    break;
                }
            
                fState = kCleaningUp;
            }
            
            case kCleaningUp:
            {
                // Cleaning up consists of making sure we've read all the incoming Request Body
                // data off of the socket
                if (this->GetRemainingReqBodyLen() > 0)
                {
                    err = this->DumpRequestData();
                    
                    if (err == EAGAIN)
                    {
                        fInputSocketP->RequestEvent(EV_RE);
                        this->ForceSameThread();    // We are holding mutexes, so we need to force
                                                    // the same thread to be used for next Run()
                        return 0;
                    }
                }

				//一次请求的读取、处理、响应过程完整,等待下一次网络报文!
                this->CleanupRequest();
                fState = kReadingRequest;
            }
        }
    } 

	//清空Session占用的所有资源
    this->CleanupRequest();

    //Session引用数为0,返回-1后,系统会将此Session删除
    if (fObjectHolders == 0)
        return -1;

	//如果流程走到这里,Session实际已经无效了,应该被删除,但没有,因为还有其他地方引用了Session对象
    return 0;
}
/* 在TCPListenerSocket中,ProcessEvent 函数(继承EventContext 的ProcessEvent()函数)被重载用来创建Socket和Task 对象得配对 */
void TCPListenerSocket::ProcessEvent(int /*eventBits*/)
{
    //we are executing on the same thread as every other
    //socket, so whatever you do here has to be fast.
	/* 该函数运行于系统唯一的EventThread 线程中,所以要尽量快速,以免占用过多的系统资源 */

	/* 在accept()中存放接受的远处客户端的ip地址 */
    struct sockaddr_in addr;
    socklen_t size = sizeof(addr);


	/* 注意theTask(通过派生类TCPSocket)和theSocket都是TCPListenerSocket的基类 */
	/**************** 注意:通过子类重载GetSessionTask()使Task(具体说,是RTSPSession)和TCPSocket配对 ***********************/
    Task* theTask = NULL;
    TCPSocket* theSocket = NULL;
    
    //fSocket data member of TCPSocket.
	/* 服务器端的Socket接受客户端的Socket的连接请求,成功后返回服务器新建的接受连接的Socket的描述符,否则返回INVALID_SOCKET */
	int osSocket = accept(fFileDesc, (struct sockaddr*)&addr, &size);

//test osSocket = -1;
	/* 假如出错了,进行错误处理.以下全是错误处理!! */
	if (osSocket == -1)
	{
        //take a look at what this error is.
		/* 获取具体的出错原因 */
        int acceptError = OSThread::GetErrno();

		/* 对得出的错误分情形讨论: */

//test acceptError = EAGAIN;
        if (acceptError == EAGAIN)
        { 
            //If it's EAGAIN, there's nothing on the listen queue right now,
            //so modwatch and return
			/* 在同一socket端口上请求监听指定的EV_RE事件 */
            this->RequestEvent(EV_RE);
            return;
        }
		
//test acceptError = ENFILE;
//test acceptError = EINTR;
//test acceptError = ENOENT;
		 
        //if these error gets returned, we're out of file descriptors, 
        //the server is going to be failing on sockets, logs, qtgroups and qtuser auth file accesses and movie files. The server is not functional.
		// 文件描述符用光,这时服务器会丧失功能,直接退出
		if (acceptError == EMFILE || acceptError == ENFILE)
        {           
			QTSSModuleUtils::LogErrorStr(qtssFatalVerbosity,  "Out of File Descriptors. Set max connections lower and check for competing usage from other processes. Exiting.");
			exit (EXIT_FAILURE);	
        }
        else //假如是其它错误(除EAGAIN\EMFILE\ENFILE以外的),在屏幕上显示错误信息,同时将配对的任务和新建的TCPSocket分别删除和关闭,并返回 
        {   
            char errStr[256];
			/* 确保末尾null-terminated */
            errStr[sizeof(errStr) -1] = 0;
			/* 得到指定格式的errStr形如"accept error = 1 '*****error' on socket. Clean up and continue." */
            qtss_snprintf(errStr, sizeof(errStr) -1, "accept error = %d '%s' on socket. Clean up and continue.", acceptError, strerror(acceptError)); 
            /* 当条件不成立时,在屏幕上显示错误信息 */
			WarnV( (acceptError == 0), errStr);
            
			/**************** 注意:通过子类重载GetSessionTask()使Task和TCPSocket配对 ***********************/
			/* 用RTSPListenerSocket::GetSessionTask()获取Session Task和socket,并对结果分析 */
            theTask = this->GetSessionTask(&theSocket);
            if (theTask == NULL)
            {   
				/* 若没有获取任务,就关闭Socket */
                close(osSocket);
            }
            else
            {  
                theTask->Signal(Task::kKillEvent); // just clean up the task
            }
            
			/* 假如RTSPSession中相对应的theSocket非空,就将其状态设为非连接 */
            if (theSocket)
                theSocket->fState &= ~kConnected; // turn off connected state
            
            return;
        }
	}/* errors handling */
	
	/* 得到Session Task并作错误处理 */
	/* 注意以后的派生类(当是RTSPListenerSocket)去获取任务,并设置好Task和outSocket */
	/**************** 注意:通过子类重载GetSessionTask()使Task和TCPSocket配对 ***********************/
    theTask = this->GetSessionTask(&theSocket);
	/* 如果没有获得任务,将已接受连接的服务器端的osSocket关闭,将服务器上RTSPSession中相对应的theSocket关闭 */
    if (theTask == NULL)
    {    //this should be a disconnect. do an ioctl call?
        close(osSocket);
        if (theSocket)
            theSocket->fState &= ~kConnected; // turn off connected state
    }
	/* 假如成功获取到任务,就分别设置这相对应的两个Socket的相关属性 */
    else//创建Task成功,接着创建Socket 对象
    {   
		/* 确保接受连接的服务器端Socket不是初始状态 */
        Assert(osSocket != EventContext::kInvalidFileDesc);
        
        //set options on the socket
        //we are a server, always disable NAGLE ALGORITHM
		/* 设置接受连接的服务器端Socket是:非延迟的,保持活跃,指定大小的传送缓存 */
        int one = 1;
        int err = ::setsockopt(osSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int));
        AssertV(err == 0, OSThread::GetErrno());
        
        err = ::setsockopt(osSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(int));
        AssertV(err == 0, OSThread::GetErrno());
    
		/* 设置服务器端传送缓存大小96K字节 */
        int sndBufSize = 96L * 1024L;
        err = ::setsockopt(osSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sndBufSize, sizeof(int));
        AssertV(err == 0, OSThread::GetErrno());
    
        //setup the socket. When there is data on the socket, theTask will get an kReadEvent event
        //
		/* 用服务器接受连接时新建的Socket和连接它的客户端的IP地址等初始化RTSPSession中的TCPSocket数据成员 */
        theSocket->Set(osSocket, &addr);
		/* 设置RTSPSession中的TCPSocket为非阻塞的 */
        theSocket->InitNonBlocking(osSocket);
		/**************** 注意:通过子类重载GetSessionTask()使Task和TCPSocket配对 ***********************/
		/* 给RTSPSession中的TCPSocket数据成员设定任务,就是它所在的RTSPSession对象实例,使RTSPSession和TCPSocket紧密配对配对 */
        theSocket->SetTask(theTask);
		// 完成上述设置后,刚建立连接的这个RTSPSession对象实例的TCPSocket向TaskThread请求读入Client发送的数据
        theSocket->RequestEvent(EV_RE);
    }  

	/* 在两次accept()间休眠吗?进行速度调整! */
    if (fSleepBetweenAccepts)
    { 	
        // We are at our maximum supported sockets
        // slow down so we have time to process the active ones (we will respond with errors or service).
        // wake up and execute again after sleeping. The timer must be reset each time through
        //qtss_printf("TCPListenerSocket slowing down\n");
		// 我们已经用光文件描述符,此处需要设置空闲任务计时器,让当前线程休眠1s
        this->SetIdleTimer(kTimeBetweenAcceptsInMsec); //sleep 1 second
    }
    else
    { 	
        // sleep until there is a read event outstanding (another client wants to connect)
        //qtss_printf("TCPListenerSocket normal speed\n");
		//处理完一次连接请求后,服务器端的侦听TCPListenerSocket对象还要接着监听,等待接入新的Client连接
        this->RequestEvent(EV_RE);
    }

    fOutOfDescriptors = false; // always false for now  we don't properly handle this elsewhere in the code
}