Пример #1
0
OS_Error HTTPClientSocket::Read(void* inBuffer, const UInt32 inLength, UInt32* outRcvLen)
{
	//
	// Bring up the GET connection if we need to
	if (!fGetSocket.IsConnected())
	{
#if CLIENT_SOCKET_DEBUG
		qtss_printf("HTTPClientSocket::Read: Sending GET\n");
#endif
		qtss_sprintf(fSendBuffer.Ptr, "GET %s HTTP/1.0\r\nX-SessionCookie: %"   _U32BITARG_   "\r\nAccept: application/x-rtsp-rtp-interleaved\r\nUser-Agent: QTSS/2.0\r\n\r\n", fURL.Ptr, fCookie);
		fSendBuffer.Len = ::strlen(fSendBuffer.Ptr);
		Assert(fSentLength == 0);
	}

	OS_Error theErr = this->Connect(&fGetSocket);
	if (theErr != OS_NoErr)
		return theErr;

	if (fSendBuffer.Len > 0)
	{
		theErr = this->SendSendBuffer(&fGetSocket);
		if (theErr != OS_NoErr)
			return theErr;
		fSentLength = 1; // So we know to execute the receive code below.
	}

	// We are done sending the GET. If we need to receive the GET response, do that here
	if (fSentLength > 0)
	{
		*outRcvLen = 0;
		do
		{
			// Loop, trying to receive the entire response.
			theErr = fGetSocket.Read(&fSendBuffer.Ptr[fGetReceived], kSendBufferLen - fGetReceived, outRcvLen);
			fGetReceived += *outRcvLen;

			// Check to see if we've gotten a \r\n\r\n. If we have, then we've received
			// the entire GET
			fSendBuffer.Ptr[fGetReceived] = '\0';
			char* theGetEnd = ::strstr(fSendBuffer.Ptr, "\r\n\r\n");

			if (theGetEnd != NULL)
			{
				// We got the entire GET response, so we are ready to move onto
				// real RTSP response data. First skip past the \r\n\r\n
				theGetEnd += 4;

#if CLIENT_SOCKET_DEBUG
				qtss_printf("HTTPClientSocket::Read: Received GET response\n");
#endif

				// Whatever remains is part of an RTSP request, so move that to
				// the beginning of the buffer and blow away the GET
				*outRcvLen = fGetReceived - (theGetEnd - fSendBuffer.Ptr);
				::memcpy(inBuffer, theGetEnd, *outRcvLen);
				fGetReceived = fSentLength = 0;
				return OS_NoErr;
			}

			Assert(fGetReceived < inLength);
		} while (*outRcvLen > 0);

#if CLIENT_SOCKET_DEBUG
		qtss_printf("HTTPClientSocket::Read: Waiting for GET response\n");
#endif
		// Message wasn't entirely received. Caller should wait for a read event on the GET socket
		Assert(theErr != OS_NoErr);
		fSocketP = &fGetSocket;
		fEventMask = EV_RE;
		return theErr;
	}

	theErr = fGetSocket.Read(&((char*)inBuffer)[fGetReceived], inLength - fGetReceived, outRcvLen);
	if (theErr != OS_NoErr)
	{
#if CLIENT_SOCKET_DEBUG
		//qtss_printf("HTTPClientSocket::Read: Waiting for data\n");
#endif
		fSocketP = &fGetSocket;
		fEventMask = EV_RE;
	}
#if CLIENT_SOCKET_DEBUG
	//else
		//qtss_printf("HTTPClientSocket::Read: Got some data\n");
#endif
	return theErr;
}
Пример #2
0
int main(int argc, char * argv[])
{
    extern char* optarg;//命令参数,例如执行:CMS.exe -d -v
    int ch;

    char* theXMLFilePath = "./config.xml";
    Bool16 notAService = false;
    Bool16 theXMLPrefsExist = true;
    Bool16 dontFork = false;

#if _DEBUG
    char* compileType = "Compile_Flags/_DEBUG; ";
#else
    char* compileType = "Compile_Flags/_RELEASE;";
#endif

    qtss_printf("%s/%s ( Build/%s; Platform/%s; %s%s) Built on: %s\n",
                QTSServerInterface::GetServerName().Ptr,
                QTSServerInterface::GetServerVersion().Ptr,
                QTSServerInterface::GetServerBuild().Ptr,
                QTSServerInterface::GetServerPlatform().Ptr,
                compileType,
                QTSServerInterface::GetServerComment().Ptr,
                QTSServerInterface::GetServerBuildDate().Ptr);

    while ((ch = getopt(argc,argv, "vdp:c:irsS:I")) != EOF) //opt: means requires option
    {
        switch(ch)
        {
        case 'v':

            qtss_printf("%s/%s ( Build/%s; Platform/%s; %s%s) Built on: %s\n",
                        QTSServerInterface::GetServerName().Ptr,
                        QTSServerInterface::GetServerVersion().Ptr,
                        QTSServerInterface::GetServerBuild().Ptr,
                        QTSServerInterface::GetServerPlatform().Ptr,
                        compileType,
                        QTSServerInterface::GetServerComment().Ptr,
                        QTSServerInterface::GetServerBuildDate().Ptr);

            qtss_printf("usage: %s [ -d | -p port | -v | -c /myconfigpath.xml | -S numseconds | -I | -h ]\n", QTSServerInterface::GetServerName().Ptr);
            qtss_printf("-d: Don't run as a Win32 Service\n");
            qtss_printf("-p 60000: Specify the default listening port of the server\n");
            qtss_printf("-c c:\\myconfigpath.xml: Specify a config file path\n");
            qtss_printf("-i: Install the CMS service\n");
            qtss_printf("-r: Remove the CMS service\n");
            qtss_printf("-s: Start the CMS service\n");
            qtss_printf("-S n: Display server stats in the console every \"n\" seconds\n");
            qtss_printf("-I: Start the server in the idle state\n");
            break;
        case 'd':
            notAService = true;
            break;
        case 'p':
            Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
            sPort = ::atoi(optarg);
            break;
        case 'c':
            Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
            theXMLFilePath = optarg;
            break;
        case 'S':
            Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
            sStatsUpdateInterval = ::atoi(optarg);
            break;
        case 'i':
            qtss_printf("Installing the CMS Server service...\n");
            ::InstallService("CMS");
            qtss_printf("Starting the CMS Server service...\n");
            ::RunAsService("CMS");
            ::exit(0);
            break;
        case 'r':
            qtss_printf("Removing the CMS Server service...\n");
            ::RemoveService("CMS");
            ::exit(0);
        case 's':
            qtss_printf("Starting the CMS Server service...\n");
            ::RunAsService("CMS");
            ::exit(0);
        case 'I':
            sInitialState = qtssIdleState;
            break;
        default:
            break;
        }
    }

    //检测软件是否过期
    QTSSExpirationDate::PrintExpirationDate();
    if (QTSSExpirationDate::IsSoftwareExpired())
    {
        qtss_printf("CMS Server Has Expired\n");
        ::exit(0);
    }

    //读取xml配置文件
    sXMLParser = new XMLPrefsParser(theXMLFilePath);

    //检测xml文件是否是以目录形式存在
    if (sXMLParser->DoesFileExistAsDirectory())
    {
        qtss_printf("Directory located at location where config prefs file should be.\n");
        ::exit(0);
    }

    //检测xml文件是否可Write
    if (!sXMLParser->CanWriteFile())
    {
        qtss_printf("Cannot write to the config prefs file.\n");
        ::exit(0);
    }

    // If we aren't forced to create a new XML prefs file, whether
    // we do or not depends solely on whether the XML prefs file exists currently.
    if (theXMLPrefsExist)
        theXMLPrefsExist = sXMLParser->DoesFileExist();

    //解析具体的xml文件
    int xmlParseErr = sXMLParser->Parse();
    if (xmlParseErr)
    {
        qtss_printf("Fatal Error: Could not load configuration file at %s. (%d)\n", theXMLFilePath, OSThread::GetErrno());
        ::exit(-1);
    }

    //根据qtssmessages.txt配置系统输出的本地化log
    sMessagesSource.InitFromConfigFile("qtssmessages.txt");

    //
    // Start Win32 DLLs
    WORD wsVersion = MAKEWORD(1, 1);
    WSADATA wsData;
    (void)::WSAStartup(wsVersion, &wsData);

    if (notAService)
    {
        // If we're running off the command-line, don't do the service initiation crap.
        ::StartServer(sXMLParser, &sMessagesSource, sPort, sStatsUpdateInterval, sInitialState, false,0, kRunServerDebug_Off); // No stats update interval for now
        ::RunServer();
        ::exit(0);
    }

    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        { "", ServiceMain },
        { NULL, NULL }
    };

    //
    // In case someone runs the server improperly, print out a friendly message.
    qtss_printf("CMS must either be started from the DOS Console\n");
    qtss_printf("using the -d command-line option, or using the Service Control Manager\n\n");
    qtss_printf("Waiting for the Service Control Manager to start CMS...\n");
    BOOL theErr = ::StartServiceCtrlDispatcher(dispatchTable);
    if (!theErr)
    {
        qtss_printf("Fatal Error: Couldn't start Service\n");
        ::exit(-1);
    }

    return (0);
}
Пример #3
0
void QTSSExpirationDate::PrintExpirationDate()
{
    if (sIsExpirationEnabled)
        qtss_printf("Software expires on: %s\n", sExpirationDate);
}
QTSS_Error RTSPRequestStream::ReadRequest()
{
    while (true)
    {
        UInt32 newOffset = 0;
        
        //If this is the case, we already HAVE a request on this session, and we now are done
        //with the request and want to move onto the next one. The first thing we should do
        //is check whether there is any lingering data in the stream. If there is, the parent
        //session believes that is part of a new request
        if (fRequestPtr != NULL)
        {
            fRequestPtr = NULL;//flag that we no longer have a complete request
            
            // Take all the retreated leftover data and move it to the beginning of the buffer
            if ((fRetreatBytes > 0) && (fRequest.Len > 0))
                ::memmove(fRequest.Ptr, fRequest.Ptr + fRequest.Len + fRetreatBytesRead, fRetreatBytes);

            // if we are decoding, we need to also move over the remaining encoded bytes
            // to the right position in the fRequestBuffer
            if (fEncodedBytesRemaining > 0)
            {
                //Assert(fEncodedBytesRemaining < 4);
                
                // The right position is at fRetreatBytes offset in the request buffer. The reason for this is:
                //  1) We need to find a place in the request buffer where we know we have enough space to store
                //  fEncodedBytesRemaining. fRetreatBytes + fEncodedBytesRemaining will always be less than
                //  kRequestBufferSize because all this data must have been in the same request buffer, together, at one point.
                //
                //  2) We need to make sure that there is always more data in the RequestBuffer than in the decoded
                //  request buffer, otherwise we could overrun the decoded request buffer (we bounds check on the encoded
                //  buffer, not the decoded buffer). Leaving fRetreatBytes as empty space in the request buffer ensures
                //  that this principle is maintained. 
                ::memmove(&fRequestBuffer[fRetreatBytes], &fRequestBuffer[fCurOffset - fEncodedBytesRemaining], fEncodedBytesRemaining);
                fCurOffset = fRetreatBytes + fEncodedBytesRemaining;
                Assert(fCurOffset < kRequestBufferSizeInBytes);
            }
            else
                fCurOffset = fRetreatBytes;
                
            newOffset = fRequest.Len = fRetreatBytes;
            fRetreatBytes = fRetreatBytesRead = 0;
        }

        // We don't have any new data, so try and get some
        if (newOffset == 0)
        {
            if (fRetreatBytes > 0)
            {
                // This will be true if we've just snarfed another input stream, in which case the encoded data
                // is copied into our request buffer, and its length is tracked in fRetreatBytes.
                // If this is true, just fall through and decode the data.
                newOffset = fRetreatBytes;
                fRetreatBytes = 0;
                Assert(fEncodedBytesRemaining == 0);
            }
            else
            {
                // We don't have any new data, get some from the socket...
                QTSS_Error sockErr = fSocket->Read(&fRequestBuffer[fCurOffset], 
                                                    (kRequestBufferSizeInBytes - fCurOffset) - 1, &newOffset);
                //assume the client is dead if we get an error back
                if (sockErr == EAGAIN)
                    return QTSS_NoErr;
                if (sockErr != QTSS_NoErr)
                {
                    Assert(!fSocket->IsConnected());
                    return sockErr;
                }
            }   

            if (fDecode)
            {
                // If we need to decode this data, do it now.
                Assert(fCurOffset >= fEncodedBytesRemaining);
                QTSS_Error decodeErr = this->DecodeIncomingData(&fRequestBuffer[fCurOffset - fEncodedBytesRemaining],
                                                                    newOffset + fEncodedBytesRemaining);
                // If the above function returns an error, it is because we've
                // encountered some non-base64 data in the stream. We can process
                // everything up until that point, but all data after this point will
                // be ignored.
                if (decodeErr == QTSS_NoErr)
                    Assert(fEncodedBytesRemaining < 4);
            }
            else
                fRequest.Len += newOffset;
            Assert(fRequest.Len < kRequestBufferSizeInBytes);
            fCurOffset += newOffset;
        }
        Assert(newOffset > 0);

        // See if this is an interleaved data packet
        if ('$' == *(fRequest.Ptr))
        {   
            if (fRequest.Len < 4)
                continue;
            UInt16* dataLenP = (UInt16*)fRequest.Ptr;
            UInt32 interleavedPacketLen = ntohs(dataLenP[1]) + 4;
            if (interleavedPacketLen > fRequest.Len)
                continue;
                
            //put back any data that is not part of the header
            fRetreatBytes += fRequest.Len - interleavedPacketLen;
            fRequest.Len = interleavedPacketLen;
        
            fRequestPtr = &fRequest;
            fIsDataPacket = true;
            return QTSS_RequestArrived;
        }
        fIsDataPacket = false;

        if (fPrintRTSP)
        {
            DateBuffer theDate;
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time
			qtss_printf("\n\n#C->S:\n#time: ms=%lu date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer());

            if (fSocket != NULL)    
            {
                UInt16 serverPort = fSocket->GetLocalPort();
                UInt16 clientPort = fSocket->GetRemotePort();    
                StrPtrLen* theLocalAddrStr = fSocket->GetLocalAddrStr();
                StrPtrLen* theRemoteAddrStr = fSocket->GetRemoteAddrStr();
                if (theLocalAddrStr != NULL)
                {	qtss_printf("#server: ip="); theLocalAddrStr->PrintStr(); qtss_printf(" port=%u\n" , serverPort );
                }
                else
              	{	qtss_printf("#server: ip=NULL port=%u\n" , serverPort );
              	}
               	
                if (theRemoteAddrStr != NULL)
                {	qtss_printf("#client: ip="); theRemoteAddrStr->PrintStr(); qtss_printf(" port=%u\n" , clientPort );
                }
            	else
            	{	qtss_printf("#client: ip=NULL port=%u\n" , clientPort );
            	}

            }

			StrPtrLen str(fRequest);
			str.PrintStrEOL("\n\r\n", "\n");// print the request but stop on \n\r\n and add a \n afterwards.
        }
        
        //use a StringParser object to search for a double EOL, which signifies the end of
        //the header.
        Bool16 weAreDone = false;
        StringParser headerParser(&fRequest);
        
        UInt16 lcount = 0;
        while (headerParser.GetThruEOL(NULL))
        {
            lcount++;
            if (headerParser.ExpectEOL())
            {
                //The legal end-of-header sequences are \r\r, \r\n\r\n, & \n\n. NOT \r\n\r!
                //If the packets arrive just a certain way, we could get here with the latter
                //combo, and not wait for a final \n.
                if ((headerParser.GetDataParsedLen() > 2) &&
                    (memcmp(headerParser.GetCurrentPosition() - 3, "\r\n\r", 3) == 0))
                    continue;
                weAreDone = true;
                break;
            }
            else if (lcount == 1) {
                // if this request is actually a ShoutCast password it will be 
                // in the form of "xxxxxx\r" where "xxxxx" is the password.
                // If we get a 1st request line ending in \r with no blanks we will
                // assume that this is the end of the request.
                UInt16 flag = 0;
                UInt16 i = 0;
                for (i=0; i<fRequest.Len; i++)
                {
                    if (fRequest.Ptr[i] == ' ')
                        flag++;
                }
                if (flag == 0)
                {
                    weAreDone = true;
                    break;
                }
            }
        }
        
        //weAreDone means we have gotten a full request
        if (weAreDone)
        {
            //put back any data that is not part of the header
            fRequest.Len -= headerParser.GetDataRemaining();
            fRetreatBytes += headerParser.GetDataRemaining();
            
            fRequestPtr = &fRequest;
            return QTSS_RequestArrived;
        }
        
        //check for a full buffer
        if (fCurOffset == kRequestBufferSizeInBytes - 1)
        {
            fRequestPtr = &fRequest;
            return E2BIG;
        }
    }
}
Пример #5
0
void Task::Signal(EventFlags events)
{
	if (!this->Valid())
		return;

	//Fancy no mutex implementation. We atomically mask the new events into
	//the event mask. Because atomic_or returns the old state of the mask,
	//we only schedule this task once.
	events |= kAlive;
	EventFlags oldEvents = atomic_or(&fEvents, events);
	if ((!(oldEvents & kAlive)) && (TaskThreadPool::sNumTaskThreads > 0))
	{
		if (fDefaultThread != NULL && fUseThisThread == NULL)
			fUseThisThread = fDefaultThread;

		if (fUseThisThread != NULL)// Task needs to be placed on a particular thread.
		{

			if (TASK_DEBUG)
			{
				if (fTaskName[0] == 0) ::strcpy(fTaskName, " _Corrupt_Task");
				qtss_printf("Task::Signal EnQueue TaskName=%s fUseThisThread=%p q_elem=%p enclosing=%p\n", fTaskName, (void *)fUseThisThread, (void *)&fTaskQueueElem, (void *) this);
				if (TaskThreadPool::sTaskThreadArray[0] == fUseThisThread) qtss_printf("Task::Signal  RTSP Thread running  TaskName=%s \n", fTaskName);
			}

			fUseThisThread->fTaskQueue.EnQueue(&fTaskQueueElem);
		}
		else
		{
			//find a thread to put this task on
			unsigned int theThreadIndex = atomic_add((unsigned int *)pickerToUse, 1);

			if (&Task::sShortTaskThreadPicker == pickerToUse)
			{
				theThreadIndex %= TaskThreadPool::sNumShortTaskThreads;

				if (TASK_DEBUG)  qtss_printf("Task::Signal EnQueue TaskName=%s using Task::sShortTaskThreadPicker=%u numShortTaskThreads=%"   _U32BITARG_   " short task range=[0-%"   _U32BITARG_   "] thread index =%u \n", fTaskName, Task::sShortTaskThreadPicker, TaskThreadPool::sNumShortTaskThreads, TaskThreadPool::sNumShortTaskThreads - 1, theThreadIndex);
			}
			else if (&Task::sBlockingTaskThreadPicker == pickerToUse)
			{
				theThreadIndex %= TaskThreadPool::sNumBlockingTaskThreads;
				theThreadIndex += TaskThreadPool::sNumShortTaskThreads; //don't pick from lower non-blocking (short task) threads.

				if (TASK_DEBUG)  qtss_printf("Task::Signal EnQueue TaskName=%s using Task::sBlockingTaskThreadPicker=%u numBlockingThreads=%"   _U32BITARG_   " blocking thread range=[%"   _U32BITARG_   "-%"   _U32BITARG_   "] thread index =%u \n", fTaskName, Task::sBlockingTaskThreadPicker, TaskThreadPool::sNumBlockingTaskThreads, TaskThreadPool::sNumShortTaskThreads, TaskThreadPool::sNumBlockingTaskThreads + TaskThreadPool::sNumShortTaskThreads - 1, theThreadIndex);
			}
			else
			{
				if (TASK_DEBUG) if (fTaskName[0] == 0) ::strcpy(fTaskName, " _Corrupt_Task");

				return;
			}


			if (TASK_DEBUG) if (fTaskName[0] == 0) ::strcpy(fTaskName, " _Corrupt_Task");

			if (TASK_DEBUG) qtss_printf("Task::Signal EnQueue B TaskName=%s theThreadIndex=%u thread=%p fTaskQueue.GetLength(%"   _U32BITARG_   ") q_elem=%p enclosing=%p\n", fTaskName, theThreadIndex, (void *)TaskThreadPool::sTaskThreadArray[theThreadIndex], TaskThreadPool::sTaskThreadArray[theThreadIndex]->fTaskQueue.GetQueue()->GetLength(), (void *)&fTaskQueueElem, (void *) this);
			TaskThreadPool::sTaskThreadArray[theThreadIndex]->fTaskQueue.EnQueue(&fTaskQueueElem);
			if (TASK_DEBUG) qtss_printf("Task::Signal EnQueue A TaskName=%s theThreadIndex=%u thread=%p fTaskQueue.GetLength(%"   _U32BITARG_   ") q_elem=%p enclosing=%p\n", fTaskName, theThreadIndex, (void *)TaskThreadPool::sTaskThreadArray[theThreadIndex], TaskThreadPool::sTaskThreadArray[theThreadIndex]->fTaskQueue.GetQueue()->GetLength(), (void *)&fTaskQueueElem, (void *) this);

		}
	}
	else
		if (TASK_DEBUG) qtss_printf("Task::Signal Sent to dead TaskName=%s  q_elem=%p  enclosing=%p\n", fTaskName, (void *)&fTaskQueueElem, (void *) this);
}
Пример #6
0
void PrintStatus(Bool16 printHeader)
{
    char* thePrefStr = NULL;
    UInt32 theLen = 0;
    
    if ( printHeader )
    {                       
        qtss_printf("     RTP-Conns RTSP-Conns HTTP-Conns  kBits/Sec   Pkts/Sec    TotConn     TotBytes   TotPktsLost          Time\n");   
    }

    (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurConn, 0, &thePrefStr);
    qtss_printf( "%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;
    
    (void)QTSS_GetValueAsString(sServer, qtssRTSPCurrentSessionCount, 0, &thePrefStr);
    qtss_printf( "%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;
    
    (void)QTSS_GetValueAsString(sServer, qtssRTSPHTTPCurrentSessionCount, 0, &thePrefStr);
    qtss_printf( "%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;
    
    UInt32 curBandwidth = 0;
    theLen = sizeof(curBandwidth);
    (void)QTSS_GetValue(sServer, qtssRTPSvrCurBandwidth, 0, &curBandwidth, &theLen);
    qtss_printf("%11"_U32BITARG_, curBandwidth/1024);
    
    (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurPackets, 0, &thePrefStr);
    qtss_printf( "%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;
    
    (void)QTSS_GetValueAsString(sServer, qtssRTPSvrTotalConn, 0, &thePrefStr);
    qtss_printf( "%11s", thePrefStr);
    delete [] thePrefStr; thePrefStr = NULL;
    
    UInt64 totalBytes = sServer->GetTotalRTPBytes();
    char  displayBuff[32] = "";
    FormattedTotalBytesBuffer(displayBuff, sizeof(displayBuff),totalBytes);
    qtss_printf( "%17s", displayBuff);
    
    qtss_printf( "%11"_64BITARG_"u", sServer->GetTotalRTPPacketsLost());
                    
    char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
    (void) QTSSRollingLog::FormatDate(theDateBuffer, false);
    qtss_printf( "%25s",theDateBuffer);
    
    qtss_printf( "\n");
    
}
Пример #7
0
BroadcasterSession::BroadcasterSession( UInt32 inAddr, UInt16 inPort, char* inURL,
                                BroadcasterType inClientType,
                                UInt32 inDurationInSec, UInt32 inStartPlayTimeInSec,
                                UInt32 inRTCPIntervalInSec, UInt32 inOptionsIntervalInSec,
                                UInt32 inHTTPCookie, Bool16 inAppendJunkData, UInt32 inReadInterval,
                                UInt32 inSockRcvBufSize,
                                StrPtrLen *sdpSPLPtr,
                                char *namePtr,
                                char *passwordPtr,
                                Bool16  deepDebug,
                                Bool16 burst)
:   fSocket(NULL),
    fRTSPClient(NULL),
    fTimeoutTask(NULL, kIdleTimeoutInMsec),

    fDurationInSec(inDurationInSec),
    fStartPlayTimeInSec(inStartPlayTimeInSec),
    fRTCPIntervalInSec(inRTCPIntervalInSec),
    fOptionsIntervalInSec(inOptionsIntervalInSec),
    
    fState(kSendingAnnounce),
    fDeathState(kSendingAnnounce),
    fDeathReason(kDiedNormally),
    fNumSetups(0),
    fUDPSocketArray(NULL),
    
    fPlayTime(0),
    fTotalPlayTime(0),
    fLastRTCPTime(0),
    fTeardownImmediately(false),
    fAppendJunk(inAppendJunkData),
    fReadInterval(inReadInterval),
    fSockRcvBufSize(inSockRcvBufSize),
    fBurst(burst),
    fBurstTime(10),
    fStats(NULL),
    fPacketLen(0),
    fChannel(0)
//  fPacket(NULL)

{
    fTimeoutTask.SetTask(this);
    StrPtrLen theURL(inURL);
    fSDPParser.Parse(sdpSPLPtr->Ptr, sdpSPLPtr->Len);
    if (fBurst && deepDebug)
        printf("Burst Mode enabled: broadcast will be delayed for %"_U32BITARG_" seconds before starting\n", fBurstTime);
        
#if BROADCAST_SESSION_DEBUG

    qtss_printf("Connecting to: %s, port %d\n", inURL, inPort);

#endif  
    //
    // Construct the appropriate ClientSocket type depending on what type of client we are supposed to be
    switch (inClientType)
    {
        case kRTSPUDPBroadcasterType:
        {
            fControlType = kRawRTSPControlType;
            fTransportType = kUDPTransportType;
            fSocket = NEW TCPClientSocket(Socket::kNonBlockingSocketType);
            break;
        }
        case kRTSPTCPBroadcasterType:
        {
            fControlType = kRawRTSPControlType;
            fTransportType = kTCPTransportType;
            fSocket = NEW TCPClientSocket(Socket::kNonBlockingSocketType);
            break;
        }
        case kRTSPHTTPBroadcasterType:
        {
            fControlType = kRTSPHTTPControlType;
            fTransportType = kTCPTransportType;
            fSocket = NEW HTTPClientSocket(theURL, inHTTPCookie, Socket::kNonBlockingSocketType);
            break;
        }
        case kRTSPHTTPDropPostBroadcasterType:
        {
            fControlType = kRTSPHTTPDropPostControlType;
            fTransportType = kTCPTransportType;
            fSocket = NEW HTTPClientSocket(theURL, inHTTPCookie, Socket::kNonBlockingSocketType);
            break;
        }
        case kRTSPReliableUDPBroadcasterType:
        {
            Assert(0);
            break;
        }
        default:
        {
            qtss_printf("BroadcasterSession: Attempt to create unsupported client type.\n");
            ::exit(-1);
        }
    }
    
    fSocket->Set(inAddr, inPort);
    fSocket->GetSocket()->SetTask(this);

    int sndBufSize = 32 * 1024;
    int rcvBufSize=1024;
    ((TCPClientSocket*)fSocket)->SetOptions(sndBufSize,rcvBufSize);
    //
    // Construct the client object using this socket.
    Bool16 verbose = deepDebug;
    fRTSPClient = NEW RTSPClient(fSocket, verbose);
    fRTSPClient->Set(theURL);
    fRTSPClient->SetTransportMode(RTSPClient::kPushMode);
    fRTSPClient->SetName(namePtr);
    fRTSPClient->SetPassword(passwordPtr);

    //
    // Start the connection process going
    this->Signal(Task::kStartEvent);
}
static Bool16 CallAuthorizeSession(QTSS_ClientSessionObject* theClientSession, QTSS_RTSPSessionObject* theRTSPSession,
        QTSS_RTSPRequestObject* theRTSPRequest, char* username, char* password) {
    qtss_printf("QTSSIcecastAuthModule::CallAuthorizeSession called\n");
    //{ :action => "listener_add", :server => "server", :port => "8000", :client => "sessionidone",
    //  :mount => "somemount.sdp", :user => "lstoll", :pass => @working_hash, :ip => "127.0.0.1", :agent => "RSPEC"}

    // generate the client session id (and save in client) format <start time millis>-<rtsp session id>
    char ice_sessid[128];

    QTSS_TimeVal clientSessCreateTime = NULL;
    UInt32 createTimeLen = sizeof (clientSessCreateTime);
    QTSS_GetValue(*theClientSession, qtssCliSesCreateTimeInMsec, 0, (void*) & clientSessCreateTime, &createTimeLen);

    char* qtssRTSPSesIDString = NULL;
    (void) QTSS_GetValueAsString(*theRTSPSession, qtssRTSPSesID, 0, &qtssRTSPSesIDString);

    sprintf(ice_sessid, "%lld-%s", clientSessCreateTime, qtssRTSPSesIDString);

    printf("QTSSIcecastAuthModule::CallAuthorizeSession generated session id: %s\n", ice_sessid);

    (void) QTSS_SetValue(*theClientSession, attrClientSessionFullSessionID, 0, &ice_sessid, sizeof (ice_sessid));

    // get the user agent
    char* userAgentString = NULL;
    (void) QTSS_GetValueAsString(*theClientSession, qtssCliSesFirstUserAgent, 0, &userAgentString);
    printf("QTSSIcecastAuthModule::CallAuthorizeSession: request user agent: %s\n", userAgentString);
    
    // get the client IP address
    char remoteAddress[20] = {0};
    StrPtrLen theClientIPAddressStr(remoteAddress,sizeof(remoteAddress));
    (void)QTSS_GetValue(*theRTSPSession, qtssRTSPSesRemoteAddrStr, 0, (void*)theClientIPAddressStr.Ptr, &theClientIPAddressStr.Len);
    
    // get the mount point
    char mountPoint[128] = {0};
    StrPtrLen mountPointStr(mountPoint,sizeof(mountPoint));
    (void)QTSS_GetValue(*theRTSPRequest, qtssRTSPReqURI, 0, (void*)mountPointStr.Ptr, &mountPointStr.Len);
    printf("QTSSIcecastAuthModule::CallAuthorizeSession: mount point: %s\n", mountPoint);
    // and set it in the client for use on session end
    (void) QTSS_SetValue(*theClientSession, attrClientSessionMountPoint, 0, mountPointStr.Ptr, mountPointStr.Len);
    
    char postdata[512];
    
    qtss_sprintf(postdata, "action=listener_add&server=%s&port=554&client=%s&mount=%s&user=%s&pass=%s&ip=%s&agent%s",
            hostname, ice_sessid, mountPoint, username, password, remoteAddress, userAgentString);
    
    
    printf("QTSSIcecastAuthModule::CallAuthorizeSession: generated postdata: %s\n", postdata);
    
    printf("QTSSIcecastAuthModule::CallAuthorizeSession: i would post this to: %s\n", sStartSessionEndpoint);
    
    return true;
    
//    
//    CURL *easyhandle = NULL; 
//    easyhandle = curl_easy_init();
//    CURLcode curl_code;
//
//    
//    curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, postdata);
//    curl_easy_setopt(easyhandle, CURLOPT_URL, "http://posthere.com/");
//    curl_easy_perform(easyhandle); /* post away! */
//
//    long http_code = 0;
//    curl_easy_getinfo(easyhandle, CURLINFO_HTTP_CODE, &http_code);
//    if (http_code == 200 && curl_code != CURLE_ABORTED_BY_CALLBACK) {
//        // the call to the remote server was OK. pass.
//        return true;
//    } else {
//        return false;
//    }
//    return false;
}
Пример #9
0
void EasyCameraSource::doStopGettingFrames() 
{
	qtss_printf("doStopGettingFrames()\n");
	netDevStopStream();
}
/*
 * This method is called because it is the only one that gets the full URL params, to capture
 * the username and password. We don't have access to the client session here, so save
 * the user and pass in the session for later. This is called BEFORE PostProcess
 */
QTSS_Error RTSPFilter(QTSS_StandardRTSP_Params* inParams) {
    QTSS_Error              theErr = QTSS_NoErr;
    QTSS_RTSPRequestObject  theRTSPRequest = inParams->inRTSPRequest;
    QTSS_RTSPSessionObject  theRTSPSession = inParams->inRTSPSession;
    
    // FAIL - can't do this here. need to finally move the auth to preprocess, and use this
    // just for param capture.
    // On the flip site, it seems that everything is really early here - if query params
    // don't work, can embed them in the URL path, extract here, and rewrite the URL in the request
    // and it should work fine. this could be handy if proxy's become an issue, because each request
    // would have a unique path.
    
//    // see if the method is bypassable. if it is, skip processing
//    qtss_printf("QTSSIcecastAuthModule::RTSPFilter: about to check if the method is bypassable\n");
//    if (IsRequestMethodBypassable(&theRTSPRequest)) return QTSS_NoErr;
    
    // see if the client is in the bypass list. if they are, skip all processing
    if (IsClientInBypassList(&theRTSPSession)) return QTSS_NoErr;
    
    // check to see if the session is already auth'd. If it is, skip processing
    if (IsRTSPSessionAuthenticated(&theRTSPSession)) {
        printf("QTSSIcecastAuthModule::RTSPFilter RTSP session is authenticated, do nothing.\n");
        return QTSS_NoErr; // we are authenticated, don't do anything
    }
    
    char* qtssRTSPSesIDString = NULL;
    (void) QTSS_GetValueAsString(theRTSPSession, qtssRTSPSesID, 0, &qtssRTSPSesIDString);
    printf("QTSSIcecastAuthModule::RTSPFilter session qtssRTSPSesID: %s\n", qtssRTSPSesIDString);
    
    char* qtssRTSPReqFullRequestString = NULL;
    (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqFullRequest, 0,  &qtssRTSPReqFullRequestString);
    qtss_printf("QTSSIcecastAuthModule::RTSPFilter: request qtssRTSPReqFullRequest: %s\n", qtssRTSPReqFullRequestString);
    
    /* will want to modify this for proper tokenization, but it works for now */ 
    char username[255];
    bool usernameset = false;
    char password[255];
    bool passwordset = false;
    
    Bool16 requiredAuthParametersProvided = false;
    
    if(index(qtssRTSPReqFullRequestString, '?')){ 
        char buf[512]; 
        snprintf(buf, 512, qtssRTSPReqFullRequestString);
        
        char* queryString;
        
        char* progress1;
        
        // split off everything after the first line, we don't need it.
        queryString = ::strtok_r(buf, "\n", &progress1); 
        // split around the ?, ignore the first part
        ::strtok_r(buf, "?", &progress1); 
        // get the second part of the previous split
        queryString = ::strtok_r(NULL, "?", &progress1); 
        // split working around the space
        queryString = ::strtok_r(queryString, " ", &progress1);
        //printf("queryString: %s\n", queryString);
        // we should now have our url
        
        char* tmp = strtok(queryString, "=&");
        
        int iters;
    
        for (iters=0; (tmp != NULL); iters++)
        {    
            char name[255]; // I'm asking for a buffer overflow, aren't I? TODO - check this.
            if ((iters % 2) != 1) {
                // even - its a name. this will always be 'first'
                strcpy(name, tmp);
                //printf("name: %s\n", tmp);
            }
            else {
                // non-even, its a value. this will always come second
                //printf("value: %s\n", tmp);
                
                if (strcmp(name, "u") == 0) {
                    // this value is the username
                    //printf("name is currently: %s. username being set to %s\n", name, tmp);
                    strcpy(username, tmp);
                    usernameset = true;
                }
                else if (strcmp(name, "p") == 0) {
                    // this value is the username
                    //printf("name is currently: %s. password being set to %s\n", name, tmp);
                    strcpy(password, tmp);
                    passwordset = true;
                }
                
            }
            tmp = strtok(NULL, "=&");
        }
        
        //printf("username: %s, password: %s\n\n", username, password);
        
        if (usernameset && passwordset) {
            printf("QTSSIcecastAuthModule::RTSPFilter username and password have been provided.\n");
            requiredAuthParametersProvided = true;
        }
        
    }
    
    if (requiredAuthParametersProvided) {
        // we have a username and password. set them on the RTSP session, so they can be validated later.
        
        QTSS_Error setErr = QTSS_SetValue(theRTSPSession, attrRtspSessionProvidedUsername, 0,  &username, sizeof(username));
        QTSS_SetValue(theRTSPSession, attrRtspSessionProvidedPassword, 0,  &password, sizeof(password));
        
        PrintQTSSError("QTSSIcecastAuthModule::RTSPFilter", "after username set", setErr);
        
        char* providedUsername = NULL;
        (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedUsername, 0,  &providedUsername);
        printf("QTSSIcecastAuthModule::RTSPFilter: Provided username extracted from session right after set: %s\n", providedUsername);

        char* providedPassword = NULL;
        (void) QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedPassword, 0, &providedPassword);
        printf("QTSSIcecastAuthModule::RTSPFilter: Provided password extracted from session right after set: %s\n", providedPassword);          
    }
    else {
        // WRONG. username and password weren't provided, do nothing - we will handle later.
    }
    
    // TODO - we should be cleaning up more things here, I think.
    QTSS_Delete(qtssRTSPReqFullRequestString);
    
    return QTSS_NoErr;
}
/*
 * This method is used to capture the full session ID details, and to reject the session. 
 * The username and password from the query string can't be grabbed here, we need to
 * do that in the Filter. This is called AFTER Filter
 */
QTSS_Error RTSPPreProcess(QTSS_StandardRTSP_Params* inParams) {
    QTSS_Error              theErr = QTSS_NoErr;
    QTSS_RTSPRequestObject  theRTSPRequest = inParams->inRTSPRequest;
    QTSS_RTSPSessionObject  theRTSPSession = inParams->inRTSPSession;
    QTSS_RTSPHeaderObject   theRTSPHeader = inParams->inRTSPHeaders;
    QTSS_ClientSessionObject theClientSession = inParams->inClientSession;

    Bool16 sessionValid = false;
    
    // see if the method is bypassable. if it is, skip processing
    qtss_printf("QTSSIcecastAuthModule::RTSPPreProcess: about to check if the method is bypassable\n");
    if (IsRequestMethodBypassable(&theRTSPRequest)) return QTSS_NoErr;
            
    //  see if the client is in the bypass list. if they are, skip all processing
    if (IsClientInBypassList(&theRTSPSession)) return QTSS_NoErr; 
    
    // check to see if the session is already auth'd. If it is, skip processing
    if (IsRTSPSessionAuthenticated(&theRTSPSession)) {
        printf("QTSSIcecastAuthModule::RTSPPreProcess RTSP session is authenticated, do nothing.\n");
        return QTSS_NoErr; // we are authenticated, don't do anything
    }
        
    
    char* providedUsername = NULL;
    (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedUsername, 0,  &providedUsername);
    printf("QTSSIcecastAuthModule::RTSPPreProcess: Provided username extracted from session: %s\n", providedUsername);
    
    char* providedPassword = NULL;
    (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedPassword, 0,  &providedPassword);
    printf("QTSSIcecastAuthModule::RTSPPreProcess: Provided password extracted from session: %s\n", providedPassword);
    
    // check to see if the username and password have been provided. If they are, process. if not
    // do nothing, we will default to an invalid session
    if (providedUsername != NULL && providedPassword != NULL) {
        
        printf("QTSSIcecastAuthModule::RTSPPreProcess: about to call authorize session\n");
        // if we get to this point we have credentials that need to be validated, so validate them.
        sessionValid = CallAuthorizeSession(&theClientSession, &theRTSPSession, &theRTSPRequest, providedUsername, providedPassword);
        
        
        
        


        // request, qtssRTSPReqFilePath - the mount point (?)
        // request, qtssRTSPReqURI - the request URI (query params parsed from here?)
        // request, qtssRTSPReqAbsoluteURL - the request url with RTSP.
        // request, qtssRTSPReqFullRequest - the full request
        // session, qtssRTSPSesID - the session id

        // note - QTSS_GetValueAsString is the least efficent method - should move to one of the more efficent methods. 
//
//    char* qtssRTSPReqFilePathString = NULL;
//    (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqFilePath, 0,  &qtssRTSPReqFilePathString);
//    printf("QTSSIcecastAuthModule::RTSPPreProcess: request qtssRTSPReqFilePath: %s\n", qtssRTSPReqFilePathString);
//
//        char* qtssRTSPReqURIString = NULL;
//        (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqURI, 0,  &qtssRTSPReqURIString);
//        printf("QTSSIcecastAuthModule::RTSPPreProcess: request qtssRTSPReqURI: %s\n", qtssRTSPReqURIString);
//
//    char* qtssRTSPReqAbsoluteURLString = NULL;
//    (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqAbsoluteURL, 0,  &qtssRTSPReqAbsoluteURLString);
//    printf("QTSSIcecastAuthModule::RTSPPreProcess: request qtssRTSPReqAbsoluteURL: %s\n", qtssRTSPReqAbsoluteURLString);

        





//        //QTSS_Delete(qtssRTSPReqFilePathString);
//        QTSS_Delete(qtssRTSPReqURIString);
//        //QTSS_Delete(qtssRTSPReqAbsoluteURLString);
//        QTSS_Delete(qtssRTSPSesIDString);
    }
    else {
        
        printf("QTSSIcecastAuthModule::RTSPPreProcess: username and/or password are NULL\n");
    }
    
    // set the auth status on the RTSP session
    (void)QTSS_SetValue(theRTSPSession, attrRtspSessionAuthenticated, 0,  &sessionValid, sizeof(sessionValid));
    
    if (sessionValid) {
        // valid session, return
        
        return QTSS_NoErr;
    }
    else {
        // not a valid session, error
        char* accessDeniedMessage = "Access DENIED";
        StrPtrLen accessDeniedMessageStr(accessDeniedMessage,sizeof(accessDeniedMessage));
        (void)QTSSModuleUtils::SendErrorResponseWithMessage(theRTSPRequest, qtssClientForbidden, &accessDeniedMessageStr);
        
        return QTSS_NoErr;
    }
}
QTSS_Error Register()
{
    QTSS_Error theErr;
    // Do role & attribute setup
    // for when the server starts
    theErr = QTSS_AddRole(QTSS_Initialize_Role);
    //PrintQTSSError("QTSSIcecastAuthModule::Register", "register for initialize role", theErr);
    // for when asked to re-read the prefs file
    
    qtss_printf("QTSSIcecastAuthModule::Register about to register for reread prefs role\n");
    (void)QTSS_AddRole(QTSS_RereadPrefs_Role);
    qtss_printf("QTSSIcecastAuthModule::Register after register for reread prefs role, about to register for filter\n");
    
    // can't find doc on these - apparently deprecated as of v3??
    //(void)QTSS_AddRole(QTSS_RTSPAuthenticate_Role);
    //(void)QTSS_AddRole(QTSS_RTSPAuthorize_Role);
    
    // the earliest call on a RTSP request - needed to get the full query including
    // query params.
    (void)QTSS_AddRole(QTSS_RTSPFilter_Role);

    // called to pre-process a RTSP request - has full client info, including timestamp
    // for completely unique session ID's (rather then the increment)
    (void)QTSS_AddRole(QTSS_RTSPPreProcessor_Role);
    
    // the shutdown role, for cleanup stuff
    (void)QTSS_AddRole(QTSS_Shutdown_Role);
    
    // The client close role, to send the end message
    (void)QTSS_AddRole(QTSS_ClientSessionClosing_Role);
    
    qtss_printf("QTSSIcecastAuthModule::Register all roles registered, about to register attributes\n");
    
    // add the attribute to hold the username when provided
    (void)QTSS_AddStaticAttribute(qtssRTSPSessionObjectType,
                            "ProvidedUsername", NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRTSPSessionObjectType, "ProvidedUsername",  &attrRtspSessionProvidedUsername);
    // add the attribute to hold the username when provided
    (void)QTSS_AddStaticAttribute(qtssRTSPSessionObjectType,
                            "ProvidedPassword", NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssRTSPSessionObjectType, "ProvidedPassword",  &attrRtspSessionProvidedPassword);
    // add the attribute that holds the flag to show if the session has been authenticated
    // we check this first, if the session is authenticated we can skip everything
    theErr = QTSS_AddStaticAttribute(qtssRTSPSessionObjectType,
                            "SessionAuthenticated", NULL, qtssAttrDataTypeBool16);
    //PrintQTSSError("QTSSIcecastAuthModule::Register", "add session authenticated attribute to rtsp session", theErr);
    theErr = QTSS_IDForAttr(qtssRTSPSessionObjectType, "SessionAuthenticated",  &attrRtspSessionAuthenticated);
    //PrintQTSSError("QTSSIcecastAuthModule::Register", "get ID for session authenticated attribute on rtsp session", theErr);
    // add to hold the 'full' session ID on the RTSP Session (start time millis CONCAT sever session id, to ensure uniqueness)
    (void)QTSS_AddStaticAttribute(qtssClientSessionObjectType,
                            "FullSessionID", NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssClientSessionObjectType, "FullSessionID",  &attrClientSessionFullSessionID);
    
    // the mount point needs to be stashed in the client session, for reporting on teardown
    (void)QTSS_AddStaticAttribute(qtssClientSessionObjectType,
                            "MountPoint", NULL, qtssAttrDataTypeCharArray);
    (void)QTSS_IDForAttr(qtssClientSessionObjectType, "MountPoint",  &attrClientSessionMountPoint);
    
    
    qtss_printf("QTSSIcecastAuthModule::Register end of method\n");
    return QTSS_NoErr; // need to return. should do something with any errors captured above.
}
Пример #13
0
// 
// 解析HTTPRequest对象fRequest报文
QTSS_Error EasyCMSSession::ProcessRequest()
{
	if(NULL == fRequest) return QTSS_BadArgument;

    //解析HTTPRequest报文
    QTSS_Error theErr = fRequest->Parse();
    if (theErr != QTSS_NoErr) return QTSS_BadArgument;

	//获取具体Content json数据部分
	StrPtrLen* lengthPtr = fRequest->GetHeaderValue(httpContentLengthHeader);
	StringParser theContentLenParser(lengthPtr);
    theContentLenParser.ConsumeWhitespace();
    UInt32 content_length = theContentLenParser.ConsumeInteger(NULL);

    if (content_length)
	{	
		qtss_printf("EasyCMSSession::ProcessRequest read content-length:%d \n", content_length);
		// 检查content的fContentBuffer和fContentBufferOffset是否有值存在,如果存在,说明我们已经开始
		// 进行content请求处理,如果不存在,我们需要创建并初始化fContentBuffer和fContentBufferOffset
		if (fContentBuffer == NULL)
		{
			fContentBuffer = NEW char[content_length + 1];
			memset(fContentBuffer,0,content_length + 1);
			fContentBufferOffset = 0;
		}
	    
		UInt32 theLen = 0;
		// 读取HTTP Content报文数据
		theErr = fInputStream.Read(fContentBuffer + fContentBufferOffset, content_length - fContentBufferOffset, &theLen);
		Assert(theErr != QTSS_BadArgument);

		if (theErr == QTSS_RequestFailed)
		{
			OSCharArrayDeleter charArrayPathDeleter(fContentBuffer);
			fContentBufferOffset = 0;
			fContentBuffer = NULL;

			return QTSS_RequestFailed;
		}
	    
		qtss_printf("EasyCMSSession::ProcessRequest() Add Len:%d \n", theLen);
		if ((theErr == QTSS_WouldBlock) || (theLen < ( content_length - fContentBufferOffset)))
		{
			//
			// Update our offset in the buffer
			fContentBufferOffset += theLen;
	       
			Assert(theErr == QTSS_NoErr);
			return QTSS_WouldBlock;
		}

		Assert(theErr == QTSS_NoErr);
	    // 处理完成报文后会自动进行Delete处理
		OSCharArrayDeleter charArrayPathDeleter(fContentBuffer);

		EasyProtocol protocol(fContentBuffer);
		int nNetMsg = protocol.GetMessageType();
		switch (nNetMsg)
		{
		case  MSG_DEV_CMS_REGISTER_RSP:
			//{	
			//	EasyDarwinRegisterRSP rsp_parse(fContentBuffer);

			//	qtss_printf("session id = %s\n", rsp_parse.GetBodyValue("SessionID").c_str());
			//	qtss_printf("device serial = %s\n", rsp_parse.GetBodyValue("DeviceSerial").c_str());
			//}
			break;
		case MSG_CMS_DEV_STREAM_START_REQ:
			{
				//EasyDarwinDeviceStreamReq	startStreamReq(fContentBuffer);
				//qtss_printf("DeviceSerial = %s\n", startStreamReq.GetBodyValue("DeviceSerial").c_str());
				//qtss_printf("CameraSerial = %s\n", startStreamReq.GetBodyValue("CameraSerial").c_str());
				//qtss_printf("DssIP = %s\n", startStreamReq.GetBodyValue("DssIP").c_str());


				//char szIP[16] = {0,};
				//strcpy(szIP, (char*)startStreamReq.GetBodyValue("DssIP").c_str());
				//qtss_printf("szIP = %s\n", szIP);
				//char *ip = (char*)startStreamReq.GetBodyValue("DssIP").c_str();
				//qtss_printf("ip = %s\n", ip);

				//QTSS_RoleParams packetParams;
				//memset(&packetParams, 0x00, sizeof(QTSS_RoleParams));
				//strcpy(packetParams.easyNVRParams.inNVRSerialNumber, (char*)sEasy_Serial);
				//strcpy(packetParams.easyNVRParams.inDeviceSerial, (char*)startStreamReq.GetBodyValue("DeviceSerial").c_str());
				//strcpy(packetParams.easyNVRParams.inCameraSerial, (char*)startStreamReq.GetBodyValue("CameraSerial").c_str());
				//packetParams.easyNVRParams.inStreamID = atoi(startStreamReq.GetBodyValue("StreamID").c_str());
				//strcpy(packetParams.easyNVRParams.inProtocol, (char*)startStreamReq.GetBodyValue("Protocol").c_str());
				//strcpy(packetParams.easyNVRParams.inDssIP, (char*)startStreamReq.GetBodyValue("DssIP").c_str());
				//packetParams.easyNVRParams.inDssPort =atoi(startStreamReq.GetBodyValue("DssPort").c_str());

				//QTSS_Error	errCode = QTSS_NoErr;
				//UInt32 fCurrentModule=0;
				//UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kStartStreamRole);
				//for (; fCurrentModule < numModules; fCurrentModule++)
				//{
				//	QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kStartStreamRole, fCurrentModule);
				//	errCode = theModule->CallDispatch(Easy_NVRStartStream_Role, &packetParams);
				//}
				//fCurrentModule = 0;

				//EasyJsonValue body;
				//body["DeviceSerial"] = packetParams.easyNVRParams.inDeviceSerial;
				//body["CameraSerial"] = packetParams.easyNVRParams.inCameraSerial;
				//body["StreamID"] = packetParams.easyNVRParams.inStreamID;
				//EasyDarwinDeviceStreamRsp rsp(body, 1, errCode == QTSS_NoErr ? 200 : 404);

				//string msg = rsp.GetMsg();
				//StrPtrLen jsonContent((char*)msg.data());
				//HTTPRequest httpAck(&sServiceStr, httpResponseType);

				//if(httpAck.CreateResponseHeader())
				//{
				//	if (jsonContent.Len)
				//		httpAck.AppendContentLengthHeader(jsonContent.Len);

				//	//Push msg to OutputBuffer
				//	char respHeader[2048] = { 0 };
				//	StrPtrLen* ackPtr = httpAck.GetCompleteHTTPHeader();
				//	strncpy(respHeader,ackPtr->Ptr, ackPtr->Len);
		
				//	fOutputStream.Put(respHeader);
				//	if (jsonContent.Len > 0) 
				//		fOutputStream.Put(jsonContent.Ptr, jsonContent.Len);
				//}
			}
			break;
		case MSG_CMS_DEV_STREAM_STOP_REQ:
			{
				//EasyDarwinDeviceStreamStop	stopStreamReq(fContentBuffer);

				//QTSS_RoleParams packetParams;
				//memset(&packetParams, 0x00, sizeof(QTSS_RoleParams));
				//strcpy(packetParams.easyNVRParams.inNVRSerialNumber, (char*)sEasy_Serial);
				//strcpy(packetParams.easyNVRParams.inDeviceSerial, (char*)stopStreamReq.GetBodyValue("DeviceSerial").data());
				//strcpy(packetParams.easyNVRParams.inCameraSerial, (char*)stopStreamReq.GetBodyValue("CameraSerial").data());
				//packetParams.easyNVRParams.inStreamID = atoi(stopStreamReq.GetBodyValue("StreamID").data());
				//strcpy(packetParams.easyNVRParams.inProtocol, "");
				//strcpy(packetParams.easyNVRParams.inDssIP, "");
				//packetParams.easyNVRParams.inDssPort = 0;

				//// 需要先判断DeviceSerial与当前设备的sEasy_Serial是否一致
				//// TODO::

				//UInt32 fCurrentModule=0;
				//QTSS_Error err = QTSS_NoErr;
				//UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kStopStreamRole);
				//for (; fCurrentModule < numModules; fCurrentModule++)
				//{
				//	QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kStopStreamRole, fCurrentModule);
				//	err = theModule->CallDispatch(Easy_NVRStopStream_Role, &packetParams);
				//}
				//fCurrentModule = 0;

				//EasyJsonValue body;
				//body["DeviceSerial"] = packetParams.easyNVRParams.inDeviceSerial;
				//body["CameraSerial"] = packetParams.easyNVRParams.inCameraSerial;
				//body["StreamID"] = packetParams.easyNVRParams.inStreamID;

				//EasyDarwinDeviceStreamStopRsp rsp(body, 1, err == QTSS_NoErr ? 200 : 404);
				//string msg = rsp.GetMsg();

				////回应
				//StrPtrLen jsonContent((char*)msg.data());
				//HTTPRequest httpAck(&sServiceStr, httpResponseType);

				//if(httpAck.CreateResponseHeader())
				//{
				//	if (jsonContent.Len)
				//		httpAck.AppendContentLengthHeader(jsonContent.Len);

				//	//Push msg to OutputBuffer
				//	char respHeader[2048] = { 0 };
				//	StrPtrLen* ackPtr = httpAck.GetCompleteHTTPHeader();
				//	strncpy(respHeader,ackPtr->Ptr, ackPtr->Len);
		
				//	fOutputStream.Put(respHeader);
				//	if (jsonContent.Len > 0) 
				//		fOutputStream.Put(jsonContent.Ptr, jsonContent.Len);
				//}
			}
			break;
		default:
			break;
		}
	}
Пример #14
0
SInt64 EasyCMSSession::Run()
{	
	OS_Error theErr = OS_NoErr;
	EventFlags events = this->GetEvents();

	if(events & Task::kKillEvent)
	{
		qtss_printf("kill event but not handle it!\n");
	}

	while(1)
	{
		switch (fState)
		{
			case kIdle://空闲
				{
					qtss_printf("kIdle state \n");

					if(!IsConnected())
					{
						// TCPSocket未连接的情况,首先进行登录连接
						Login();
					}
					else
					{
						// TCPSocket已连接的情况下区分具体事件类型
						if(events & Task::kStartEvent)
						{
							// CMSSession掉线,重新进行上线动作
							if(kSessionOffline == fSessionStatus)
								Login();
						}

						if(events & Task::kReadEvent)
						{
							// 对已连接的TCP进行消息读取
							fState = kReadingRequest;
						}
						if(events & Task::kTimeoutEvent)
						{
							// 保活时间到,需要发送保活报文
							Login();
						}
					}
					
					// 如果有消息需要发送则进入发送流程
					if (fOutputStream.GetBytesWritten() > 0)
					{
						fState = kSendingResponse;
					}

					if(kIdle == fState) return 0;

					break;
				}

			case kReadingRequest:
				{
					qtss_printf("kReadingRequest state \n");

					// 读取锁,已经在处理一个报文包时,不进行新网络报文的读取和处理
					OSMutexLocker readMutexLocker(&fReadMutex);

					// 网络请求报文存储在fInputStream中
					if ((theErr = fInputStream.ReadRequest()) == QTSS_NoErr)
					{
						//如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据
						//但,还不能构成一个整体报文,还要继续等待读取...
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(EV_RE);
						return 0;
					}
                
					if ((theErr != QTSS_RequestArrived) && (theErr != E2BIG) && (theErr != 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(theErr > 0);
						// 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(!fSocket->GetSocket()->IsConnected());
						this->ResetClientSocket();

						return 0;
					}
					fState = kProcessingRequest;
					break;
				}
			case kProcessingRequest:
				{
					qtss_printf("kProcessingRequest state \n");
					// 处理网络报文
					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 (theErr == E2BIG)
					{
						// 返回HTTP报文,错误码408
						//(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgRequestTooLong);
						fState = kSendingResponse;
						break;
					}
					// Check for a corrupt base64 error, return an error
					if (theErr == QTSS_BadArgument)
					{
						//返回HTTP报文,错误码408
						//(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64);
						fState = kSendingResponse;
						break;
					}

					Assert(theErr == QTSS_RequestArrived);
					ProcessRequest();

					// 每一步都检测响应报文是否已完成,完成则直接进行回复响应
					if (fOutputStream.GetBytesWritten() > 0)
					{
						fState = kSendingResponse;
					}
					else
					{
						fState = kCleaningUp;
					}
					break;
				}
			case kSendingResponse:
				{
					qtss_printf("kSendingResponse state \n");

					// 响应报文发送,确保完全发送
					// Assert(fRequest != NULL);

					//发送响应报文
					theErr = fOutputStream.Flush();
                
					if (theErr == EAGAIN || theErr == EINPROGRESS)
					{
						// If we get this error, we are currently flow-controlled and should
						// wait for the socket to become writeable again
						// 如果收到Socket EAGAIN错误,那么我们需要等Socket再次可写的时候再调用发送
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask());
						this->ForceSameThread();
						// We are holding mutexes, so we need to force
						// the same thread to be used for next Run()
						return 0;
					}
					else if (theErr != QTSS_NoErr)
					{
						// Any other error means that the client has disconnected, right?
						Assert(!this->IsConnected());
						ResetClientSocket();
						return 0;
					}
            
					fState = kCleaningUp;
					break;
				}
			case kCleaningUp:
				{
					qtss_printf("kCleaningUp state \n");
					// 清理已经处理的请求或者已经发送的报文缓存
					// 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 = kIdle;
					
					if(IsConnected())
					{
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask());
					}
					return 0;
				}
		}
	}
    return 0;
}
Пример #15
0
QTSS_Error QTAccessFile::AuthorizeRequest(QTSS_StandardRTSP_Params* inParams, Bool16 allowNoAccessFiles, QTSS_ActionFlags noAction, QTSS_ActionFlags authorizeAction, Bool16 *outAuthorizedPtr, Bool16 *outAllowAnyUserPtr)
{
    if  ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) || (NULL == outAllowAnyUserPtr) || (NULL == outAuthorizedPtr)  )
        return QTSS_RequestFailed;

    *outAllowAnyUserPtr = false;
    *outAuthorizedPtr = false;
    
    QTSS_RTSPRequestObject  theRTSPRequest = inParams->inRTSPRequest;
    
    // get the type of request
    // Don't touch write requests
    QTSS_ActionFlags action = QTSSModuleUtils::GetRequestActions(theRTSPRequest);
    if(action == qtssActionFlagsNoFlags)
        return QTSS_RequestFailed;
    
    if( (action & noAction) != 0)
        return QTSS_NoErr; // we don't handle
    
    //get the local file path
    char*   pathBuffStr = QTSSModuleUtils::GetLocalPath_Copy(theRTSPRequest);
    OSCharArrayDeleter pathBuffDeleter(pathBuffStr);
    if (NULL == pathBuffStr)
        return QTSS_RequestFailed;

    //get the root movie directory
    char*   movieRootDirStr = QTSSModuleUtils::GetMoviesRootDir_Copy(theRTSPRequest);
    OSCharArrayDeleter movieRootDeleter(movieRootDirStr);
    if (NULL == movieRootDirStr)
        return QTSS_RequestFailed;
    
    QTSS_UserProfileObject theUserProfile = QTSSModuleUtils::GetUserProfileObject(theRTSPRequest);
    if (NULL == theUserProfile)
        return QTSS_RequestFailed;

    char* accessFilePath = QTAccessFile::GetAccessFile_Copy(movieRootDirStr, pathBuffStr);
    OSCharArrayDeleter accessFilePathDeleter(accessFilePath);
        
    char* username = QTSSModuleUtils::GetUserName_Copy(theUserProfile);
    OSCharArrayDeleter usernameDeleter(username);

    UInt32 numGroups = 0;
    char** groupCharPtrArray =  QTSSModuleUtils::GetGroupsArray_Copy(theUserProfile, &numGroups);
    OSCharPointerArrayDeleter groupCharPtrArrayDeleter(groupCharPtrArray);
    
    StrPtrLen accessFileBuf;
    (void)QTSSModuleUtils::ReadEntireFile(accessFilePath, &accessFileBuf);
    OSCharArrayDeleter accessFileBufDeleter(accessFileBuf.Ptr);
        
    if (accessFileBuf.Len == 0 && !allowNoAccessFiles)
    {   accessFileBuf.Set(sAccessValidUser);
        if (DEBUG_QTACCESS) 
            qtss_printf("QTAccessFile::AuthorizeRequest SET Accessfile valid user for no accessfile %s\n", sAccessValidUser);
    }
      
    if (accessFileBuf.Len == 0 && allowNoAccessFiles)
    {   accessFileBuf.Set(sAccessAnyUser);
        if (DEBUG_QTACCESS) 
            qtss_printf("QTAccessFile::AuthorizeRequest SET Accessfile any user for no access file %s\n", sAccessAnyUser);
    }
      
    char realmName[kBuffLen] = { 0 };
    StrPtrLen   realmNameStr(realmName,kBuffLen -1);
    
    //check if this user is allowed to see this movie
    Bool16 allowRequest = this->AccessAllowed(username, groupCharPtrArray, numGroups,  &accessFileBuf, authorizeAction,&realmNameStr, outAllowAnyUserPtr );
    debug_printf("accessFile.AccessAllowed for user=%s returned %d\n", username, allowRequest);
    
    // Get the auth scheme
    QTSS_AuthScheme theAuthScheme = qtssAuthNone;
    UInt32 len = sizeof(theAuthScheme);
    QTSS_Error theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqAuthScheme, 0, (void*)&theAuthScheme, &len);
    Assert(len == sizeof(theAuthScheme));
    if(theErr != QTSS_NoErr)
        return theErr;
    
    // If auth scheme is basic and the realm is present in the access file, use it
    if((theAuthScheme == qtssAuthBasic) && (realmNameStr.Ptr[0] != '\0'))   //set the realm if we have one
        (void) QTSS_SetValue(theRTSPRequest,qtssRTSPReqURLRealm, 0, realmNameStr.Ptr, ::strlen(realmNameStr.Ptr));
    else // if auth scheme is basic and no realm is present, or if the auth scheme is digest, use the realm from the users file
    {  
        char*   userRealm = NULL;   
        (void) QTSS_GetValueAsString(theUserProfile, qtssUserRealm, 0, &userRealm);
        if(userRealm != NULL)
        {
            OSCharArrayDeleter userRealmDeleter(userRealm);
            (void) QTSS_SetValue(theRTSPRequest,qtssRTSPReqURLRealm, 0, userRealm, ::strlen(userRealm));
        }
    }
    
    *outAuthorizedPtr = allowRequest;
    
    Bool16 founduser = this->HaveUser(username, NULL);
    Bool16 authContinue = true;
    char nameBuff[256];
    StrPtrLen reqNameStr(nameBuff, kBuffLen);
    StrPtrLen profileNameStr(username);
    theErr = QTSS_GetValue (theRTSPRequest,qtssRTSPReqUserName,0, (void *) reqNameStr.Ptr, &reqNameStr.Len);
 
    
if (DEBUG_QTACCESS)
{   qtss_printf("QTAccessFile::AuthorizeRequest qtaccess profile user =%s ", username);
    reqNameStr.PrintStr("request user="******"\n");
    qtss_printf("QTAccessFile::AuthorizeRequest allowRequest=%d founduser=%d authContinue=%d\n", allowRequest, founduser, authContinue);
}   
    if (allowRequest && founduser)
        theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &founduser,&authContinue);
    if (!allowRequest && !founduser)
        theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &founduser,&authContinue);

if (DEBUG_QTACCESS)
{   qtss_printf("QTAccessFile::AuthorizeRequest QTSSModuleUtils::AuthorizeRequest qtaccess profile user =%s ", username);
    reqNameStr.PrintStr("request user="******"\n");
    qtss_printf("QTAccessFile::AuthorizeRequest allowRequest=%d founduser=%d authContinue=%d\n", allowRequest, founduser, authContinue);
}   
 
    return theErr;
}
Пример #16
0
int main(int argc, char * argv[]) 
{
    extern char* optarg;
    
    

    // on write, don't send signal for SIGPIPE, just set errno to EPIPE
    // and return -1
    //signal is a deprecated and potentially dangerous function
    //(void) ::signal(SIGPIPE, SIG_IGN);
    struct sigaction act;
    
#if defined(sun) || defined(i386) || defined(__x86_64__) || defined (__MacOSX__) || defined(__powerpc__) || defined (__osf__) || defined (__sgi_cc__) || defined (__hpux__) || defined (__linux__)
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_handler = (void(*)(int))&sigcatcher;
#elif defined(__sgi__) 
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = (void(*)(...))&sigcatcher;
#else
    act.sa_mask = 0;
    act.sa_flags = 0;
    act.sa_handler = (void(*)(...))&sigcatcher;
#endif
    (void)::sigaction(SIGPIPE, &act, NULL);
    (void)::sigaction(SIGHUP, &act, NULL);
    (void)::sigaction(SIGINT, &act, NULL);
    (void)::sigaction(SIGTERM, &act, NULL);
    (void)::sigaction(SIGQUIT, &act, NULL);
    (void)::sigaction(SIGALRM, &act, NULL);


#if __solaris__ || __linux__ || __hpux__
    //grow our pool of file descriptors to the max!
    struct rlimit rl;
    
    // set it to the absolute maximum that the operating system allows - have to be superuser to do this
    rl.rlim_cur = RLIM_INFINITY;
    rl.rlim_max = RLIM_INFINITY;
 
    setrlimit (RLIMIT_NOFILE, &rl);
#endif

#if __MacOSX__
    struct rlimit rl;
    getrlimit(RLIMIT_NOFILE,  &rl); //get the default values
    //printf("current open file limit =%"_U32BITARG_"\n", (UInt32) rl.rlim_cur); //leopard returns  256
    //printf("current open file max =%"_U32BITARG_"\n", (UInt32) rl.rlim_max);//leopard returns infinity (-1)
    
    rl. rlim_max = (rlim_t) RLIM_INFINITY -1; //use a big number to find out the real max but do not use RLIM_INFINITY that is not allowed. see man page
    setrlimit (RLIMIT_NOFILE, &rl); //resets the max value stored by limits to the boot config values.
    getrlimit(RLIMIT_NOFILE,  &rl); //now get the real max value
    //printf("current open file limit =%"_U32BITARG_"\n", (UInt32) rl.rlim_cur);
    //printf("current open file max =%"_U32BITARG_"\n", (UInt32) rl.rlim_max);
    
    rl.rlim_cur = (rlim_t) ( (float) rl.rlim_max * 0.9);   //use 90% of the max set in /etc/rc.server and /etc/sysctl.conf.default
    setrlimit (RLIMIT_NOFILE, &rl);  //finally set the current limit 
    
#endif
    
#if 0 // testing
    getrlimit(RLIMIT_NOFILE,  &rl);
    printf("current open file limit =%"_U32BITARG_"\n", (UInt32) rl.rlim_cur);
    printf("current open file max =%"_U32BITARG_"\n", (UInt32) rl.rlim_max);
#endif

#if __MacOSX__ || __FreeBSD__
        //
        // These 2 OSes have problems with large socket buffer sizes. Make sure they allow even
        // ridiculously large ones, because we may need them to receive a large volume of ACK packets
        // from the client
        
        //
        // We raise the limit imposed by the kernel by calling the sysctl system call.
        int mib[CTL_MAXNAME];
        mib[0] = CTL_KERN;
        mib[1] = KERN_IPC;
        mib[2] = KIPC_MAXSOCKBUF;
        mib[3] = 0;

        int maxSocketBufferSizeVal = 2000 * 1024; // Allow up to 2 MB. That is WAY more than we should need
        (void) ::sysctl(mib, 3, 0, 0, &maxSocketBufferSizeVal, sizeof(maxSocketBufferSizeVal));
        //int sysctlErr =  ::sysctl(mib, 3, 0, 0, &maxSocketBufferSizeVal, sizeof(maxSocketBufferSizeVal));
        //qtss_printf("sysctl maxSocketBufferSizeVal=%d err=%d\n",maxSocketBufferSizeVal, sysctlErr);
 #endif
    
    //First thing to do is to read command-line arguments.
    int ch;
    int thePort = 0; //port can be set on the command line
    int statsUpdateInterval = 0;
    QTSS_ServerState theInitialState = qtssRunningState;
    
    Bool16 dontFork = false;
    Bool16 theXMLPrefsExist = true;
    UInt32 debugLevel = 0;
    UInt32 debugOptions = kRunServerDebug_Off;
	static char* sDefaultConfigFilePath = DEFAULTPATHS_ETC_DIR_OLD "easydarwin.conf";
	static char* sDefaultXMLFilePath = DEFAULTPATHS_ETC_DIR "easydarwin.xml";

    char* theConfigFilePath = sDefaultConfigFilePath;
    char* theXMLFilePath = sDefaultXMLFilePath;
    while ((ch = getopt(argc,argv, "vdfxp:DZ:c:o:S:Ih")) != EOF) // opt: means requires option arg
    {
        switch(ch)
        {
            case 'v':
                usage();
                ::exit(0);  
            case 'd':
                dontFork = RunInForeground();
                
                break;                
            case 'D':
               dontFork = RunInForeground();

               debugOptions |= kRunServerDebugDisplay_On;
                
               if (debugLevel == 0)
                    debugLevel = 1;
                    
               if (statsUpdateInterval == 0)
                    statsUpdateInterval = 3;
                    
               break;            
            case 'Z':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                debugLevel = (UInt32) ::atoi(optarg);
                                
                break;
            case 'f':
				theXMLFilePath  = DEFAULTPATHS_ETC_DIR "easydarwin.xml";
                break;
            case 'p':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                thePort = ::atoi(optarg);
                break;
            case 'S':
                dontFork = RunInForeground();
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                statsUpdateInterval = ::atoi(optarg);
                break;
            case 'c':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                theXMLFilePath = optarg;
                break;
            case 'o':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                theConfigFilePath = optarg;
                break;
            case 'x':
                theXMLPrefsExist = false; // Force us to generate a new XML prefs file
                theInitialState = qtssShuttingDownState;
                dontFork = true;
                break;
            case 'I':
                theInitialState = qtssIdleState;
                break;
            case 'h':
                usage();
                ::exit(0);
            default:
                break;
        }
    }
    
  
    // Check port
    if (thePort < 0 || thePort > 65535)
    { 
        qtss_printf("Invalid port value = %d max value = 65535\n",thePort);
        exit (-1);
    }

    // Check expiration date
    QTSSExpirationDate::PrintExpirationDate();
    if (QTSSExpirationDate::IsSoftwareExpired())
    {
        qtss_printf("Streaming Server has expired\n");
        ::exit(0);
    }


    XMLPrefsParser theXMLParser(theXMLFilePath);
    
    //
    // Check to see if the XML file exists as a directory. If it does,
    // just bail because we do not want to overwrite a directory
    if (theXMLParser.DoesFileExistAsDirectory())
    {
        qtss_printf("Directory located at location where streaming server prefs file should be.\n");
        exit(-1);
    }
    
    //
    // Check to see if we can write to the file
    if (!theXMLParser.CanWriteFile())
    {
        qtss_printf("Cannot write to the streaming server prefs file.\n");
        exit(-1);
    }

    // If we aren't forced to create a new XML prefs file, whether
    // we do or not depends solely on whether the XML prefs file exists currently.
    if (theXMLPrefsExist)
        theXMLPrefsExist = theXMLParser.DoesFileExist();
    
    if (!theXMLPrefsExist)
    {
        
        //
        // The XML prefs file doesn't exist, so let's create an old-style
        // prefs source in order to generate a fresh XML prefs file.
        
        if (theConfigFilePath != NULL)
        {   
            FilePrefsSource* filePrefsSource = new FilePrefsSource(true); // Allow dups
            
            if ( filePrefsSource->InitFromConfigFile(theConfigFilePath) )
            { 
               qtss_printf("Generating a new prefs file at %s\n", theXMLFilePath);
            }

            if (GenerateAllXMLPrefs(filePrefsSource, &theXMLParser))
            {
                qtss_printf("Fatal Error: Could not create new prefs file at: %s. (%d)\n", theXMLFilePath, OSThread::GetErrno());
                ::exit(-1);
            }
        }
    }

 
    //
    // Parse the configs from the XML file
    int xmlParseErr = theXMLParser.Parse();
    if (xmlParseErr)
    {
        qtss_printf("Fatal Error: Could not load configuration file at %s. (%d)\n", theXMLFilePath, OSThread::GetErrno());
        ::exit(-1);
    }
    
    //Unless the command line option is set, fork & daemonize the process at this point
    if (!dontFork)
    {
#ifdef __sgi__
		// for some reason, this method doesn't work right on IRIX 6.4 unless the first arg
		// is _DF_NOFORK.  if the first arg is 0 (as it should be) the result is a server
		// that is essentially paralized and doesn't respond to much at all.  So for now,
		// leave the first arg as _DF_NOFORK
//		if (_daemonize(_DF_NOFORK, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO) != 0)
        if (_daemonize(0, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO) != 0)
#else
        if (daemon(0,0) != 0)
#endif
        {
#if DEBUG
            qtss_printf("Failed to daemonize process. Error = %d\n", OSThread::GetErrno());
#endif
            exit(-1);
        }
    }
    
    //Construct a Prefs Source object to get server text messages
    FilePrefsSource theMessagesSource;
    theMessagesSource.InitFromConfigFile("qtssmessages.txt");
    

    int status = 0;
    int pid = 0;
    pid_t processID = 0;
	
    if ( !dontFork) // if (fork) 
    {
        //loop until the server exits normally. If the server doesn't exit
        //normally, then restart it.
        // normal exit means the following
        // the child quit 
        do // fork at least once but stop on the status conditions returned by wait or if autoStart pref is false
        {
            processID = fork();
            Assert(processID >= 0);
            if (processID > 0) // this is the parent and we have a child
            {
                sChildPID = processID;
                status = 0;
                while (status == 0) //loop on wait until status is != 0;
                {	
                 	pid =::wait(&status);
                 	SInt8 exitStatus = (SInt8) WEXITSTATUS(status);
                	//qtss_printf("Child Process %d wait exited with pid=%d status=%d exit status=%d\n", processID, pid, status, exitStatus);
                	
					if (WIFEXITED(status) && pid > 0 && status != 0) // child exited with status -2 restart or -1 don't restart 
					{
						//qtss_printf("child exited with status=%d\n", exitStatus);
						
						if ( exitStatus == -1) // child couldn't run don't try again
						{
							qtss_printf("child exited with -1 fatal error so parent is exiting too.\n");
							exit (EXIT_FAILURE); 
						}
						break; // restart the child
							
					}
					
					if (WIFSIGNALED(status)) // child exited on an unhandled signal (maybe a bus error or seg fault)
					{	
						//qtss_printf("child was signalled\n");
						break; // restart the child
					}

                 		
                	if (pid == -1 && status == 0) // parent woken up by a handled signal
                   	{
						//qtss_printf("handled signal continue waiting\n");
                   		continue;
                   	}
                   	
                 	if (pid > 0 && status == 0)
                 	{
                 		//qtss_printf("child exited cleanly so parent is exiting\n");
                 		exit(EXIT_SUCCESS);                		
                	}
                	
                	//qtss_printf("child died for unknown reasons parent is exiting\n");
                	exit (EXIT_FAILURE);
                }
            }
            else if (processID == 0) // must be the child
				break;
            else
            	exit(EXIT_FAILURE);
            	
            	
            //eek. If you auto-restart too fast, you might start the new one before the OS has
            //cleaned up from the old one, resulting in startup errors when you create the new
            //one. Waiting for a second seems to work
            sleep(1);
        } while (RestartServer(theXMLFilePath)); // fork again based on pref if server dies
        if (processID != 0) //the parent is quitting
        	exit(EXIT_SUCCESS);   

        
    }
    sChildPID = 0;
    //we have to do this again for the child process, because sigaction states
    //do not span multiple processes.
    (void)::sigaction(SIGPIPE, &act, NULL);
    (void)::sigaction(SIGHUP, &act, NULL);
    (void)::sigaction(SIGINT, &act, NULL);
    (void)::sigaction(SIGTERM, &act, NULL);
    (void)::sigaction(SIGQUIT, &act, NULL);

#ifdef __hpux__  
	// Set Priority Type to Real Time, timeslice = 100 milliseconds. Change the timeslice upwards as needed. This keeps the server priority above the playlist broadcaster which is a time-share scheduling type.
	char commandStr[64];
	qtss_sprintf(commandStr, "/usr/bin/rtprio -t -%d", (int) getpid()); 
#if DEBUG
	qtss_printf("setting priority to Real Time: %s\n", commandStr);
#endif
	(void) ::system(commandStr);    
#endif
    
#ifdef __solaris__  
    // Set Priority Type to Real Time, timeslice = 100 milliseconds. Change the timeslice upwards as needed. This keeps the server priority above the playlist broadcaster which is a time-share scheduling type.
    char commandStr[64];
    qtss_sprintf(commandStr, "priocntl -s -c RT -t 10 -i pid %d", (int) getpid()); 
    (void) ::system(commandStr);    
#endif

#ifdef __MacOSX__
    (void) ::umask(S_IWGRP|S_IWOTH); // make sure files are opened with default of owner -rw-r-r-
#endif

    //This function starts, runs, and shuts down the server
    if (::StartServer(&theXMLParser, &theMessagesSource, thePort, statsUpdateInterval, theInitialState, dontFork, debugLevel, debugOptions) != qtssFatalErrorState)
    {    ::RunServer();
         CleanPid(false);
         exit (EXIT_SUCCESS);
    }
    else
    	exit(-1); //Cant start server don't try again
}
Пример #17
0
OS_Error    OSFileSource::ReadFromCache(UInt64 inPosition, void* inBuffer, UInt32 inLength, UInt32* outRcvLen)
{ 
    OSMutexLocker locker(&fMutex);
    
    if (!fFileMap.Initialized() || !fCacheEnabled)
    {   Assert(0);
    }
    
    Assert(outRcvLen != NULL);
    *outRcvLen = 0;
        
   if (inPosition >= fLength) // eof
        return OS_NoErr;

    SInt64 buffIndex = fFileMap.GetBuffIndex(inPosition);   
    SInt64 buffSize = 0;
    SInt64 maxBuffSize = fFileMap.GetMaxBufSize();
    SInt64 endIndex = fFileMap.GetBuffIndex(inPosition+inLength);
    SInt64 maxIndex = fFileMap.GetMaxBuffIndex();
    SInt64 buffPos =  inPosition - fFileMap.GetBuffOffset(buffIndex);
    SInt64 buffOffsetLen = 0;
    char *buffStart = NULL;
    SInt64 buffCopyLen = inLength;
    SInt64 bytesToCopy = inLength;
    char *buffOut = (char*)inBuffer;
    Bool16 fillBuff = true;
    char *buffOffset = NULL;
    
#if FILE_SOURCE_BUFFTEST
    char testBuff[inLength + 1];
    buffOut = (char*)testBuff;
    sBuffCount ++;
    ::memset(inBuffer,0,inLength);  
    ::memset(testBuff,0,inLength);
#endif
    
    if (buffIndex > endIndex || endIndex > maxIndex)
    {
#if FILE_SOURCE_DEBUG

        qtss_printf("OSFileSource::ReadFromCache bad index: buffIndex=%" _S32BITARG_ " endIndex=%" _S32BITARG_ " maxIndex=%" _S32BITARG_ "\n",buffIndex,endIndex,maxIndex);
        qtss_printf("OSFileSource::ReadFromCache inPosition =%qu buffSize = %"   _U32BITARG_   " index=%" _S32BITARG_ "\n",inPosition, fFileMap.GetMaxBufSize(),buffIndex);
#endif
        Assert(0);
    }
        
   while (buffIndex <= endIndex && buffIndex <= maxIndex)
   {    
#if FILE_SOURCE_DEBUG
        qtss_printf("OSFileSource::ReadFromCache inPosition =%qu buffSize = %"   _U32BITARG_   " index=%" _S32BITARG_ "\n",inPosition, fFileMap.GetMaxBufSize(),buffIndex);
#endif

        buffStart = fFileMap.GetBuffer(buffIndex, &fillBuff);
        Assert(buffStart != NULL);
        
        if (fillBuff)
        {
            OS_Error theErr = this->FillBuffer( (char *) inBuffer, (char *) buffStart, (SInt32) buffIndex);
            if (theErr != OS_NoErr)
                return theErr;
            
        }
        
        
        buffSize = fFileMap.GetBuffSize(buffIndex);
        buffOffset = &buffStart[buffPos];
        
        if  (   (buffPos == 0) && 
                (bytesToCopy <= maxBuffSize) && 
                (buffSize < bytesToCopy)
            ) // that's all there is in the file
        {
                
            #if FILE_SOURCE_DEBUG
                qtss_printf("OSFileSource::ReadFromCache end of file reached buffIndex=%"   _U32BITARG_   " buffSize = %" _S32BITARG_ " bytesToCopy=%"   _U32BITARG_   "\n",buffIndex, buffSize,bytesToCopy);
            #endif
            Assert(buffSize <= (SInt64) kUInt32_Max);
            ::memcpy(buffOut,buffOffset,(UInt32) buffSize);
            *outRcvLen += (UInt32) buffSize;
            break;
        }

        buffOffsetLen = buffSize - buffPos;
        if (buffCopyLen >= buffOffsetLen)
            buffCopyLen = buffOffsetLen;
            
        Assert(buffCopyLen <= buffSize);

        ::memcpy(buffOut,buffOffset, (UInt32) buffCopyLen);
        buffOut += buffCopyLen;
        *outRcvLen += (UInt32) buffCopyLen;
        bytesToCopy -= buffCopyLen;
        Assert(bytesToCopy >= 0);
        
        buffCopyLen = bytesToCopy;
        buffPos = 0;
        buffIndex ++;
            
    } 
    
#if FILE_SOURCE_DEBUG
        //qtss_printf("OSFileSource::ReadFromCache inLength= %"   _U32BITARG_   " *outRcvLen=%"   _U32BITARG_   "\n",inLength, *outRcvLen);
#endif

#if FILE_SOURCE_BUFFTEST    
    {   UInt32 outLen = 0;
        OS_Error theErr = this->ReadFromPos(inPosition, inBuffer, inLength, &outLen);       
        
        Assert(*outRcvLen == outLen);
        if (*outRcvLen != outLen)
            qtss_printf("OSFileSource::ReadFromCache *outRcvLen != outLen *outRcvLen=%"   _U32BITARG_   " outLen=%"   _U32BITARG_   "\n",*outRcvLen,outLen);
            
        for (int i = 0; i < inLength; i++)
        {   if ( ((char*)inBuffer)[i] != testBuff[i])
            {   qtss_printf("OSFileSource::ReadFromCache byte pos %d of %"   _U32BITARG_   " failed len=%"   _U32BITARG_   " inPosition=%qu sBuffCount=%" _S32BITARG_ "\n",i,inLength,outLen,inPosition,sBuffCount);
                break;
            }
        }
    }
#endif

    return OS_NoErr;
}
Пример #18
0
void usage()
{
    const char *usage_name = PLATFORM_SERVER_BIN_NAME;
//long ptrsize = sizeof(char *); printf("size of ptr = %ld\n", ptrsize);
//long longsize = sizeof(long); printf("size of long = %ld\n", longsize);

   qtss_printf("%s/%s ( Build/%s; Platform/%s; %s) Built on: %s\n",QTSServerInterface::GetServerName().Ptr,
                                        QTSServerInterface::GetServerVersion().Ptr,
                                        QTSServerInterface::GetServerBuild().Ptr,
                                        QTSServerInterface::GetServerPlatform().Ptr,
                                        QTSServerInterface::GetServerComment().Ptr,
                                        QTSServerInterface::GetServerBuildDate().Ptr);
    qtss_printf("usage: %s [ -d | -p port | -v | -c /myconfigpath.xml | -o /myconfigpath.conf | -x | -S numseconds | -I | -h ]\n", usage_name);
    qtss_printf("-d: Run in the foreground\n");
    qtss_printf("-D: Display performance data\n");
    qtss_printf("-p XXX: Specify the default RTSP listening port of the server\n");
    qtss_printf("-c /myconfigpath.xml: Specify a config file\n");
    qtss_printf("-o /myconfigpath.conf: Specify a DSS 1.x / 2.x config file to build XML file from\n");
    qtss_printf("-x: Force create new .xml config file and exit.\n");
    qtss_printf("-S n: Display server stats in the console every \"n\" seconds\n");
    qtss_printf("-I: Start the server in the idle state\n");
    qtss_printf("-h: Prints usage\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();

    Socket::Initialize();
    SocketUtils::Initialize(!inDontFork);

#if !MACOSXEVENTQUEUE
    ::select_startevents();//initialize the select() implementation of the event queue
#endif
    
    //start the server
    QTSSDictionaryMap::Initialize();
    QTSServerInterface::Initialize();// this must be called before constructing the server object
    sServer = NEW QTSServer();
    sServer->SetDebugLevel(debugLevel);
    sServer->SetDebugOptions(debugOptions);
    
    // re-parse config file
    inPrefsSource->Parse();

    Bool16 createListeners = true;
    if (qtssShuttingDownState == inInitialState) 
        createListeners = false;
    
    sServer->Initialize(inPrefsSource, inMessagesSource, inPortOverride,createListeners);

    if (inInitialState == qtssShuttingDownState)
    {  
        sServer->InitModules(inInitialState);
        return inInitialState;
    }
    
    OSCharArrayDeleter runGroupName(sServer->GetPrefs()->GetRunGroupName());
    OSCharArrayDeleter runUserName(sServer->GetPrefs()->GetRunUserName());
    OSThread::SetPersonality(runUserName.GetObject(), runGroupName.GetObject());

    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)
    {
        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();
        sServer->SetupUDPSockets(); // udp sockets are set up after the rtcp task is instantiated
        theServerState = sServer->GetServerState();
    }

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

        doneStartingUp = true;
        qtss_printf("Streaming Server done starting up\n");
        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;
}
Пример #20
0
//登录用户验证
Bool16 Easy_UserAuthentication(const char* inUserName, const char* inPassword)
{
	qtss_printf("User:%s Password:%s Authenticated!\n");
	return true;
}
int main(int argc, char *argv[])
{
    FILE *usersFilePtr = NULL, *tempUsersFilePtr = NULL, *passFilePtr = NULL, *groupsFilePtr = NULL;
    //char line[MAX_STRING_LEN + 1];
    char line[MAX_LINE_LEN];
    char lineFromFile[MAX_LINE_LEN];
    char usernameFromFile[MAX_STRING_LEN + 1];
    char realmFromFile[MAX_STRING_LEN + 1];
    int found;
    int result;
    static char choice[81];

    int doCreateNewFile = 0;
    int doDeleteUser = 0;
	int addUserToGroup = 0;
	int deleteUserFromGroup = 0;
	int createGroup = 0;
	int deleteGroup = 0;
    int confirmPotentialDamage = 1;
    char* qtusersFilePath = NULL;
	char* qtgroupsFilePath = NULL;
    char* userName = NULL;
	char* groupName = NULL;
    char* realmString = NULL;
    char* password = NULL;
    char* passwordFilePath = NULL;
    int ch;
    extern char* optarg;
    extern int optind;

	/* Read command line arguments */
    while ((ch = getopt(argc, argv, "f:cg:r:p:P:A:D:C:R:dFhv?")) != EOF)
    {
        switch(ch) 
        {

            case 'f':
                    qtusersFilePath = CopyString(optarg);
            break;
			
            case 'c':
                    doCreateNewFile = 1;
            break;
			
            case 'g':
                    qtgroupsFilePath = CopyString(optarg);
            break;
			
            case 'r':
                    realmString = CopyString(optarg);
                    if (::strlen(realmString) > MAX_STRING_LEN)
                    {
                        qtss_fprintf(stderr, "Realm cannot have more than %d characters.\n", MAX_STRING_LEN);
                        qtss_printf("Exiting! \n");
                        exit(1);
                    }
            break;

            case 'p':
                    password = CopyString(optarg);
					::memset(optarg, 0, ::strlen(optarg));
					
                    if (::strlen(password) > MAX_PASSWORD_LEN)
                    {
                        qtss_fprintf(stderr, "Password cannot have more than %d characters.\n", MAX_PASSWORD_LEN);
                        qtss_printf("Exiting! \n");
                        exit(1);
                    }
            break;

            case 'P':
                    passwordFilePath = CopyString(optarg);
            break;

            case 'A':
                    groupName = CopyString(optarg);
					addUserToGroup = 1;
            break;

            case 'D':
                    groupName = CopyString(optarg);
					deleteUserFromGroup = 1;
            break;

            case 'C':
                    groupName = CopyString(optarg);
					createGroup = 1;
            break;

            case 'R':
                    groupName = CopyString(optarg);
					deleteGroup = 1;
            break;			

            case 'd':
                    doDeleteUser = 1;
            break;
			
            case 'F':
                    confirmPotentialDamage = 0;
            break;

        case 'h':
        case 'v':
            case '?':
            default:
                usage(); 
            break;
        }
    }

	/* If password is to be read from a file, check validity of the password */
	if ((password == NULL) && (passwordFilePath != NULL))
    {
		if ((passFilePtr = fopen(passwordFilePath, "r")) != NULL ) 
		{
			char passline[MAX_STRING_LEN];
			char passFromFile[MAX_STRING_LEN];
			int passLen = 0;
			
			::memset(passline, 0, MAX_STRING_LEN);
			::memset(passFromFile, 0, MAX_STRING_LEN);
			
			GetLine(passline, MAX_STRING_LEN, passFilePtr);
	
			if (passline[0] == '\'')        // if it is single quoted, read until the end single quote
				GetWord(passFromFile, (passline + 1), '\'');
			else if (passline[0] == '"')        // if it is double quoted, read until the end double quote
				GetWord(passFromFile, (passline + 1), '"');
			else                    // if it is not quoted, read until the first whitespace
				GetWord(passFromFile, passline, ' ');
				
			passLen = ::strlen(passFromFile);
				
			if (passLen == 0)
			{
				qtss_fprintf(stderr, "Password in file %s is blank.\n", passwordFilePath);
				qtss_printf("Exiting! \n");
				exit(1);
			}
			else if (passLen > MAX_PASSWORD_LEN)
			{
				qtss_fprintf(stderr, "Password in file %s has more than %d characters. Cannot accept password.\n", passwordFilePath, MAX_PASSWORD_LEN);
				qtss_printf("Exiting! \n");
				exit(1);
			}
			else
				password = CopyString(passFromFile);

            fclose(passFilePtr);
        }
    }

    /* deleting a user and (creating a file or setting a password) don't make sense together */
    if ( doDeleteUser && (doCreateNewFile || password != NULL) )
    {
		qtss_fprintf(stderr, "Cannot use the -c option (to create the file) with the -d option (to delete the user).\n");
		qtss_printf("Exiting! \n");
        usage();
    }

    /* realm name only makes sense when creating a new password file */
    if ( !doCreateNewFile && (realmString != NULL) )
    {
		qtss_fprintf(stderr, "Can use the -r option only with the -c option (when creating the file).\n");
		qtss_printf("Exiting! \n");
		usage();
    }

	/* group name checks */
	if (groupName != NULL) 
	{
		/* check length < MAX_STRING_LEN */
		if (::strlen(groupName) > MAX_STRING_LEN)
		{
			qtss_fprintf(stderr, "Group name cannot have more than %d characters.\n", MAX_STRING_LEN);
			qtss_printf("Exiting! \n");
			exit(1);
		}	
		
		/* check for : */
        if (strchr(groupName, ':') != NULL) 
        {
            qtss_printf("Group name cannot contain a ':' character.\n");
			qtss_printf("Exiting! \n");
			exit(1);
        }
		
		/* can't add user to group and delete user from a group at the same time */
		if (addUserToGroup && deleteUserFromGroup)
        {
            qtss_printf("Cannot add to or delete from a group at the same time (use either -A or -D option, not both!).\n");
			qtss_printf("Exiting! \n");
			exit(1);
        }
		
		/* can't create and delete group at the same time */
		if (createGroup && deleteGroup)
        {
            qtss_printf("Cannot create new group and delete group at the same time (use either -C or -R option, not both!).\n");
			qtss_printf("Exiting! \n");
			exit(1);
        }
	}

	/* Read in the username */
    if (argv[optind] != NULL)
    {
		/* If group needs to be created or deleted, username will be ignored. */
		if (createGroup || deleteGroup)
		{
			qtss_fprintf(stderr, "Warning: username cannot be specified with -C or -R option and will be ignored!\n");
		}
		else
		{
			userName = CopyString(argv[optind]);
			
			/* check length < MAX_STRING_LEN */		
			if (::strlen(userName) > MAX_STRING_LEN)
			{
			qtss_fprintf(stderr, "Username cannot have more than %d characters.\n", MAX_STRING_LEN);
			qtss_printf("Exiting! \n");
			exit(1);
			}
		}
    }
    else
	{
		/* Exit if username is not given, unless a group has to be created or deleted. */
		if (!createGroup && !deleteGroup)
		{
			qtss_fprintf(stderr, "Username not given!\n");
			qtss_printf("Exiting! \n");
			usage();
		}
    }

    if (confirmPotentialDamage && doDeleteUser)
    {
        qtss_printf("Delete user %s (will also delete user from groups in the groups file)? y or n [y] ", userName);
        fgets( (char*)&choice, 80, stdin);
        if( choice[0] == 'n' || choice[0] == 'N' ) 
            exit(0);
    }

    if (qtusersFilePath == NULL)
    {
        qtusersFilePath = new char[strlen(kDefaultQTPasswdFilePath)+1];
        strcpy(qtusersFilePath, kDefaultQTPasswdFilePath);
    }

    if (qtgroupsFilePath == NULL)
    {
        qtgroupsFilePath = new char[strlen(kDefaultQTGroupsFilePath)+1];
        strcpy(qtgroupsFilePath, kDefaultQTGroupsFilePath);
    }
	
    if (realmString  == NULL)
    {
        char* kDefaultRealmString = "Streaming Server";

        realmString = new char[strlen(kDefaultRealmString)+1];
        strcpy(realmString, kDefaultRealmString);
    }

    
    tempUsersFile = NULL;
	tempGroupsFile = NULL;
	
#ifndef __Win32__
    signal(SIGINT, (void(*)(int))CleanupAndExit);
    //create file with owner RW permissions only
    umask(S_IRWXO|S_IRWXG);
#endif

    if (doCreateNewFile)
    {
        if (confirmPotentialDamage)
            if( (usersFilePtr = fopen(qtusersFilePath, "r")) != NULL ) 
            {
                fclose(usersFilePtr);
    
                qtss_printf("File already exists. Do you wish to overwrite it? y or n [y] ");
                fgets( (char*)&choice, 80, stdin);
                if( choice[0] == 'n' || choice[0] == 'N' ) 
                    CleanupAndExit();
                    
            }

        //create new file or truncate existing one to 0
        if ( (usersFilePtr = fopen(qtusersFilePath, "w")) == NULL)
        {   
			char buffer[kErrorStrSize];
            qtss_fprintf(stderr, "Could not open password file %s for writing. (err=%d %s)\n", qtusersFilePath, errno, qtss_strerror(errno, buffer, sizeof(buffer)));
            perror("fopen");
            CleanupAndExit();
        }

        qtss_printf("Creating password file for realm %s.\n", realmString);

        //write the realm into the file
        qtss_fprintf(usersFilePtr, "realm %s\n", realmString);

        fclose(usersFilePtr);
	    SetPrivileges(qtusersFilePath);


    }

#ifdef __Win32__
    char separator = '\\';
#else
    char separator = '/';
#endif
	char* tmpFile = "tmp.XXXXXX";
	char* alternateTempPath = "./tmp.XXXXXX";
    char* tempFilePath;
	int	tempFilePathLength = 0;
    char* lastOccurOfSeparator = strrchr(qtusersFilePath, separator);
    int pathLength = strlen(qtusersFilePath);
	
    if(lastOccurOfSeparator != NULL) 
    {
		int filenameLength = ::strlen(lastOccurOfSeparator) + sizeof(char);
		tempFilePathLength = pathLength - filenameLength + sizeof(char) + ::strlen(tmpFile);
		
		tempFilePath = new char[tempFilePathLength];
		memcpy(tempFilePath, qtusersFilePath, (pathLength - filenameLength));
		memcpy(tempFilePath + (pathLength - filenameLength), tmpFile, ::strlen(tmpFile));
		tempFilePath[pathLength - filenameLength + ::strlen(tmpFile)] = '\0';
		
		/* Get temp users file path name */
		if (!createGroup && !deleteGroup)
			tempUsersFile = GetTempFileAtPath(tempFilePath, tempFilePathLength);

		/* Get temp groups file path name */		
		if ((groupName != NULL) || doDeleteUser)
			tempGroupsFile = GetTempFileAtPath(tempFilePath, tempFilePathLength);
		
		delete [] tempFilePath;
    }
    else 
    {
		if (!createGroup && !deleteGroup)
			tempUsersFile = GetTempFileAtPath(alternateTempPath, ::strlen(alternateTempPath));
		if ((groupName != NULL) || doDeleteUser)
			tempGroupsFile = GetTempFileAtPath(alternateTempPath, ::strlen(alternateTempPath));
	}
		
	if ((groupName != NULL) && !(groupsFilePtr = fopen(qtgroupsFilePath, "r")))
	{
		char buffer[kErrorStrSize];
		qtss_fprintf(stderr, "Could not open groups file %s to manipulate groups file. (err=%d:%s)\n", qtgroupsFilePath, errno,  qtss_strerror(errno, buffer, sizeof(buffer)));
				
		//create new file
        if ( (groupsFilePtr = fopen(qtgroupsFilePath, "w")) == NULL)
        {   
			char buffer[kErrorStrSize];
            qtss_fprintf(stderr, "Could not create a new groups file %s either. (err=%d %s)\n", qtgroupsFilePath, errno, qtss_strerror(errno, buffer, sizeof(buffer)));
			CleanupAndExit();
        }
		else
			qtss_printf("Created new groups file %s.\n", qtgroupsFilePath);

        fclose(groupsFilePtr);
	    SetPrivileges(qtgroupsFilePath);
	}
	
	if (createGroup)
	{
		AddOrDeleteGroup(1, groupName, qtgroupsFilePath, tempGroupsFile);
		qtss_printf("Created new group %s\n", groupName);
		return 0;
	}
	
	if (deleteGroup)
	{
		AddOrDeleteGroup(0, groupName, qtgroupsFilePath, tempGroupsFile);
		qtss_printf("Deleted group %s\n", groupName);
		return 0;
	}
	
    if (!(tempUsersFilePtr = fopen(tempUsersFile, "w"))) 
    {   
        char buffer[kErrorStrSize];
        qtss_printf("failed\n");
        qtss_fprintf(stderr, "Could not open temp users file. (err=%d %s)\n", errno,  qtss_strerror(errno, buffer, sizeof(buffer)));
		CleanupAndExit();
    }
	
    if (!(usersFilePtr = fopen(qtusersFilePath, "r")))
    {   
        char buffer[kErrorStrSize];
        qtss_fprintf(stderr, "Could not open passwd file %s for reading. (err=%d:%s)\n", qtusersFilePath, errno,  qtss_strerror(errno, buffer, sizeof(buffer)));
        qtss_fprintf(stderr, "Use -c option to create new one.\n");
		CleanupAndExit();
    }

    // Get the realm from the first line
    while (!(GetLine(line, MAX_LINE_LEN, usersFilePtr))) 
    {
        if ((line[0] == '#') || (!line[0]))
        {
            PutLine(tempUsersFilePtr, line);
            continue;
        }
        else
        {
            // line is "realm somename"
            if( strncmp(line, "realm", strlen("realm")) != 0 )
            {
                    qtss_fprintf(stderr, "Invalid users file.\n");
                    qtss_fprintf(stderr, "The first non-comment non-blank line must be the realm line\n");
                    qtss_fprintf(stderr, "The file may have been tampered manually!\n");				
					CleanupAndExit();
            }
            strcpy(realmFromFile ,line + strlen("realm")+1); 
            PutLine(tempUsersFilePtr, line);
            break;  
        }
    }
    // Look for an existing entry with the username
    found = 0;
    while (!(GetLine(line, MAX_LINE_LEN, usersFilePtr))) 
    {
        //write comments and blank lines out to temp file
        if (found || (line[0] == '#') || (line[0] == 0)) 
        {
            PutLine(tempUsersFilePtr, line);
            continue;
        }
        strcpy(lineFromFile, line);
        GetWord(usernameFromFile, lineFromFile, ':');

        //if not the user we're looking for, write the line out to the temp file
        if (strcmp(userName, usernameFromFile) != 0) 
        {
            PutLine(tempUsersFilePtr, line);
            continue;
        }
        else 
        {
            if (doDeleteUser)
            {   //to delete a user - just don't write it out to the temp file
                qtss_printf("Deleting user %s\n", userName);
				//delete user from all groups in the group file
				qtss_printf("Deleting user %s from all groups\n", userName);
				AddOrDeleteUserFromGroup(0, userName, NULL, qtgroupsFilePath, tempGroupsFile);
				
            }
            else
            {
				if (addUserToGroup)
				{
					PutLine(tempUsersFilePtr, line);
					
					qtss_printf("Adding user %s to group %s\n", userName, groupName);
					AddOrDeleteUserFromGroup(1, userName, groupName, qtgroupsFilePath, tempGroupsFile);
				}
				else if (deleteUserFromGroup)
				{
					PutLine(tempUsersFilePtr, line);
					
					qtss_printf("Deleting user %s from group %s\n", userName, groupName);
					AddOrDeleteUserFromGroup(0, userName, groupName, qtgroupsFilePath, tempGroupsFile);
				}
				else
				{
					qtss_printf("Changing password for user %s\n", userName);
					if(password != NULL)
						AddPasswordWithoutPrompt(userName, password, realmFromFile, tempUsersFilePtr);
					else 
						AddPassword(userName, realmFromFile, tempUsersFilePtr);
				}
            }
            found = 1;
        }
    }
    
    if (!found) 
    {
        if (doDeleteUser)
        {
            qtss_printf("Username %s not found in users file.\n", userName);
			
			//delete user from all groups in the group file
			qtss_printf("Deleting user %s from all groups if found in groups file\n", userName);
			AddOrDeleteUserFromGroup(0, userName, NULL, qtgroupsFilePath, tempGroupsFile);
			CleanupAndExit();
        }

        /* check for : in name before adding user */
        if(strchr(userName, ':') != NULL) 
        {
            qtss_printf("Username cannot contain a ':' character.");
			CleanupAndExit();
        }
    
        qtss_printf("Adding userName %s\n", userName);
        if(password != NULL)
            AddPasswordWithoutPrompt(userName, password, realmFromFile, tempUsersFilePtr);
        else 
            AddPassword(userName, realmFromFile, tempUsersFilePtr);
			
		if (addUserToGroup)
		{
			qtss_printf("Adding user %s to group %s\n", userName, groupName);
			AddOrDeleteUserFromGroup(1, userName, groupName, qtgroupsFilePath, tempGroupsFile);
		}
		else if (deleteUserFromGroup)
		{
			qtss_printf("Deleting user %s from group %s\n", userName, groupName);
			AddOrDeleteUserFromGroup(0, userName, groupName, qtgroupsFilePath, tempGroupsFile);
		}
    }
    	
    fclose(usersFilePtr);
    fclose(tempUsersFilePtr);
    
    // Remove old file and change name of temp file to match new file
    remove(qtusersFilePath);
    
    result = rename(tempUsersFile, qtusersFilePath);
    if(result != 0)
	{
        perror("rename failed with error");
		CleanupAndExit();
	}
	SetPrivileges(qtusersFilePath);

    return 0;
}
Пример #22
0
void APITests_DEBUG()
{
    if (0)
    {   qtss_printf("QTSSAdminModule start tests \n");
    
        if (0)
        {
            qtss_printf("admin called locked \n");
            const int ksleeptime = 15;
            qtss_printf("sleeping for %d seconds \n",ksleeptime);
            sleep(ksleeptime);
            qtss_printf("done sleeping \n");
            qtss_printf("QTSS_GlobalUnLock \n");
            (void) QTSS_GlobalUnLock();
            qtss_printf("again sleeping for %d seconds \n",ksleeptime);
            sleep(ksleeptime);
        }
    
        if (0)
        {
            qtss_printf(" GET VALUE PTR TEST \n");

            QTSS_Object *sessionsPtr = NULL;
            UInt32      paramLen = sizeof(sessionsPtr);
            UInt32      numValues = 0;
            QTSS_Error  err = 0;
            
            err = QTSS_GetNumValues (sServer, qtssSvrClientSessions, &numValues);
            err = QTSS_GetValuePtr(sServer, qtssSvrClientSessions, 0, (void**)&sessionsPtr, &paramLen);
            qtss_printf("Admin Module Num Sessions = %"_U32BITARG_" sessions[0] = %"_S32BITARG_" err = %"_S32BITARG_" paramLen =%"_U32BITARG_"\n", numValues, (SInt32) *sessionsPtr,err,paramLen);
    
            UInt32      numAttr = 0;
            if (sessionsPtr)
            {   err = QTSS_GetNumAttributes (*sessionsPtr, &numAttr);
                qtss_printf("Admin Module Num attributes = %"_U32BITARG_" sessions[0] = %"_S32BITARG_"  err = %"_S32BITARG_"\n", numAttr, (SInt32) *sessionsPtr,err);
        
                QTSS_Object theAttributeInfo;
                char nameBuff[128];
                UInt32 len = 127;
                for (UInt32 i = 0; i < numAttr; i++)
                {   err = QTSS_GetAttrInfoByIndex(*sessionsPtr, i, &theAttributeInfo);
                    nameBuff[0] = 0;len = 127;
                    err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
                    nameBuff[len] = 0;
                    qtss_printf("found %s \n",nameBuff);
                }
            }
        }
        
        if (0)
        {
            qtss_printf(" GET VALUE TEST \n");

            QTSS_Object sessions = NULL;
            UInt32      paramLen = sizeof(sessions);
            UInt32      numValues = 0;
            QTSS_Error  err = 0;
            
            err = QTSS_GetNumValues (sServer, qtssSvrClientSessions, &numValues);
            err = QTSS_GetValue(sServer, qtssSvrClientSessions, 0, (void*)&sessions, &paramLen);
            qtss_printf("Admin Module Num Sessions = %"_U32BITARG_" sessions[0] = %"_S32BITARG_" err = %"_S32BITARG_" paramLen = %"_U32BITARG_"\n", numValues, (SInt32) sessions,err, paramLen);
            
            if (sessions)
            {
                UInt32      numAttr = 0;
                err = QTSS_GetNumAttributes (sessions, &numAttr);
                qtss_printf("Admin Module Num attributes = %"_U32BITARG_" sessions[0] = %"_S32BITARG_"  err = %"_S32BITARG_"\n", numAttr,(SInt32) sessions,err);
                
                QTSS_Object theAttributeInfo;
                char nameBuff[128];
                UInt32 len = 127;
                for (UInt32 i = 0; i < numAttr; i++)
                {   err = QTSS_GetAttrInfoByIndex(sessions, i, &theAttributeInfo);
                    nameBuff[0] = 0;len = 127;
                    err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
                    nameBuff[len] = 0;
                    qtss_printf("found %s \n",nameBuff);
                }
            }
        }
        

        if (0)
        {
            qtss_printf("----------------- Start test ----------------- \n");
            qtss_printf(" GET indexed pref TEST \n");

            QTSS_Error  err = 0;
            
            UInt32      numAttr = 1;
            err = QTSS_GetNumAttributes (sModulePrefs, &numAttr);
            qtss_printf("Admin Module Num preference attributes = %"_U32BITARG_" err = %"_S32BITARG_"\n", numAttr, err);
                
            QTSS_Object theAttributeInfo;
            char valueBuff[512];
            char nameBuff[128];
            QTSS_AttributeID theID;
            UInt32 len = 127;
            UInt32 i = 0;
            qtss_printf("first pass over preferences\n");
            for ( i = 0; i < numAttr; i++)
            {   err = QTSS_GetAttrInfoByIndex(sModulePrefs, i, &theAttributeInfo);
                nameBuff[0] = 0;len = 127;
                err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
                nameBuff[len]=0;

                theID = qtssIllegalAttrID; len = sizeof(theID);
                err = QTSS_GetValue (theAttributeInfo, qtssAttrID,0, &theID,&len);
                qtss_printf("found preference=%s \n",nameBuff);
            }
            valueBuff[0] = 0;len = 512;
            err = QTSS_GetValue (sModulePrefs, theID,0, valueBuff,&len);valueBuff[len] = 0;
            qtss_printf("Admin Module QTSS_GetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
            err = QTSS_SetValue (sModulePrefs,theID,0, valueBuff,len);
            qtss_printf("Admin Module QTSS_SetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
            
            {   QTSS_ServiceID id;
                (void) QTSS_IDForService(QTSS_REREAD_PREFS_SERVICE, &id);           
                (void) QTSS_DoService(id, NULL);
            }

            valueBuff[0] = 0;len = 512;
            err = QTSS_GetValue (sModulePrefs, theID,0, valueBuff,&len);valueBuff[len] = 0;
            qtss_printf("Admin Module QTSS_GetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
            err = QTSS_SetValue (sModulePrefs,theID,0, valueBuff,len);
            qtss_printf("Admin Module QTSS_SetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
                
            qtss_printf("second pass over preferences\n");
            for ( i = 0; i < numAttr; i++)
            {   err = QTSS_GetAttrInfoByIndex(sModulePrefs, i, &theAttributeInfo);
                nameBuff[0] = 0;len = 127;
                err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
                nameBuff[len]=0;

                theID = qtssIllegalAttrID; len = sizeof(theID);
                err = QTSS_GetValue (theAttributeInfo, qtssAttrID,0, &theID,&len);
                qtss_printf("found preference=%s \n",nameBuff);
            }
            qtss_printf("----------------- Done test ----------------- \n");
        }
            
    }
}
Пример #23
0
void TaskThread::Entry()
{
	Task* theTask = NULL;

	while (true)
	{
		theTask = this->WaitForTask();

		//
		// WaitForTask returns NULL when it is time to quit
		if (theTask == NULL || false == theTask->Valid())
			return;

		Bool16 doneProcessingEvent = false;

		while (!doneProcessingEvent)
		{
			//If a task holds locks when it returns from its Run function,
			//that would be catastrophic and certainly lead to a deadlock
#if DEBUG
			Assert(this->GetNumLocksHeld() == 0);
			Assert(theTask->fInRunCount == 0);
			theTask->fInRunCount++;
#endif
			theTask->fUseThisThread = NULL; // Each invocation of Run must independently
											// request a specific thread.
			SInt64 theTimeout = 0;

			if (theTask->fWriteLock)
			{
				OSMutexWriteLocker mutexLocker(&TaskThreadPool::sMutexRW);
				if (TASK_DEBUG) qtss_printf("TaskThread::Entry run global locked TaskName=%s CurMSec=%.3f thread=%p task=%p\n", theTask->fTaskName, OS::StartTimeMilli_Float(), (void *) this, (void *)theTask);

				theTimeout = theTask->Run();
				theTask->fWriteLock = false;
			}
			else
			{
				OSMutexReadLocker mutexLocker(&TaskThreadPool::sMutexRW);
				if (TASK_DEBUG) qtss_printf("TaskThread::Entry run TaskName=%s CurMSec=%.3f thread=%p task=%p\n", theTask->fTaskName, OS::StartTimeMilli_Float(), (void *) this, (void *)theTask);

				theTimeout = theTask->Run();

			}
#if DEBUG
			Assert(this->GetNumLocksHeld() == 0);
			theTask->fInRunCount--;
			Assert(theTask->fInRunCount == 0);
#endif          
			if (theTimeout < 0)
			{
				if (TASK_DEBUG)
				{
					qtss_printf("TaskThread::Entry delete TaskName=%s CurMSec=%.3f thread=%p task=%p\n", theTask->fTaskName, OS::StartTimeMilli_Float(), (void *) this, (void *)theTask);

					theTask->fUseThisThread = NULL;

					if (NULL != fHeap.Remove(&theTask->fTimerHeapElem))
						qtss_printf("TaskThread::Entry task still in heap before delete\n");

					if (NULL != theTask->fTaskQueueElem.InQueue())
						qtss_printf("TaskThread::Entry task still in queue before delete\n");

					theTask->fTaskQueueElem.Remove();

					if (theTask->fEvents &~Task::kAlive)
						qtss_printf("TaskThread::Entry flags still set  before delete\n");

					(void)atomic_sub(&theTask->fEvents, 0);

					::strncat(theTask->fTaskName, " deleted", sizeof(theTask->fTaskName) - 1);
				}
				theTask->fTaskName[0] = 'D'; //mark as dead
				delete theTask;
				theTask = NULL;
				doneProcessingEvent = true;

			}
			else if (theTimeout == 0)
			{
				//We want to make sure that 100% definitely the task's Run function WILL
				//be invoked when another thread calls Signal. We also want to make sure
				//that if an event sneaks in right as the task is returning from Run()
				//(via Signal) that the Run function will be invoked again.
				doneProcessingEvent = compare_and_store(Task::kAlive, 0, &theTask->fEvents);
				if (doneProcessingEvent)
					theTask = NULL;
			}
			else
			{
				//note that if we get here, we don't reset theTask, so it will get passed into
				//WaitForTask
				if (TASK_DEBUG) qtss_printf("TaskThread::Entry insert TaskName=%s in timer heap thread=%p elem=%p task=%p timeout=%.2f\n", theTask->fTaskName, (void *) this, (void *)&theTask->fTimerHeapElem, (void *)theTask, (float)theTimeout / (float)1000);
				theTask->fTimerHeapElem.SetValue(OS::Milliseconds() + theTimeout);
				fHeap.Insert(&theTask->fTimerHeapElem);
				(void)atomic_or(&theTask->fEvents, Task::kIdleEvent);
				doneProcessingEvent = true;
			}


#if TASK_DEBUG
			SInt64  yieldStart = OS::Milliseconds();
#endif

			this->ThreadYield();
#if TASK_DEBUG
			SInt64  yieldDur = OS::Milliseconds() - yieldStart;
			static SInt64   numZeroYields;

			if (yieldDur > 1)
			{
				if (TASK_DEBUG) qtss_printf("TaskThread::Entry time in Yield %qd, numZeroYields %qd \n", yieldDur, numZeroYields);
				numZeroYields = 0;
			}
			else
				numZeroYields++;
#endif

		}
	}
}
Пример #24
0
Bool16  Authenticate(QTSS_RTSPRequestObject request, StrPtrLen* namePtr, StrPtrLen* passwordPtr)
{
    Bool16 authenticated = true;
    
    char* authName = namePtr->GetAsCString();
    OSCharArrayDeleter authNameDeleter(authName);
    
    QTSS_ActionFlags authAction = qtssActionFlagsAdmin;
    
    // authenticate callback to retrieve the password 
    QTSS_Error err = QTSS_Authenticate(authName, sAuthResourceLocalPath, sAuthResourceLocalPath, authAction, qtssAuthBasic, request);
    if (err != QTSS_NoErr) {
         return false; // Couldn't even call QTSS_Authenticate...abandon!
    }
    
    // Get the user profile object from the request object that was created in the authenticate callback
    QTSS_UserProfileObject theUserProfile = NULL;
    UInt32 len = sizeof(QTSS_UserProfileObject);
    err = QTSS_GetValue(request, qtssRTSPReqUserProfile, 0, (void*)&theUserProfile, &len);
    Assert(len == sizeof(QTSS_UserProfileObject));
    if (err != QTSS_NoErr)
        authenticated = false;

    if(err == QTSS_NoErr) {
        char* reqPassword = passwordPtr->GetAsCString();
        OSCharArrayDeleter reqPasswordDeleter(reqPassword);
        char* userPassword = NULL;  
        (void) QTSS_GetValueAsString(theUserProfile, qtssUserPassword, 0, &userPassword);
        OSCharArrayDeleter userPasswordDeleter(userPassword);
    
        if(userPassword == NULL) {
            authenticated = false;
        }
        else {
#ifdef __Win32__
            // The password is md5 encoded for win32
            char md5EncodeResult[120];
            MD5Encode(reqPassword, userPassword, md5EncodeResult, sizeof(md5EncodeResult));
            if(::strcmp(userPassword, md5EncodeResult) != 0)
                authenticated = false;
#else
            if(::strcmp(userPassword, (char*)crypt(reqPassword, userPassword)) != 0)
                authenticated = false;
#endif
        }
    }
    
    char* realm = NULL;
    Bool16 allowed = true;
    //authorize callback to check authorization
    // allocates memory for realm
	err = QTSS_Authorize(request, &realm, &allowed);
	// QTSS_Authorize allocates memory for the realm string
	// we don't use the realm returned by the callback, but instead 
	// use our own.
	// delete the memory allocated for realm because we don't need it!
	OSCharArrayDeleter realmDeleter(realm);
    
    if(err != QTSS_NoErr) {
        qtss_printf("QTSSAdminModule::Authenticate: QTSS_Authorize failed\n");
        return false; // Couldn't even call QTSS_Authorize...abandon!
    }
    
    if(authenticated && allowed)
        return true;
        
    return false;
}
Пример #25
0
//Windows服务控制
void WINAPI ServiceControl(DWORD inControlCode)
{
    QTSS_ServerState theState;
    QTSServerInterface* theServer = QTSServerInterface::GetServer();
    DWORD theStatusReport = SERVICE_START_PENDING;

    if (theServer != NULL)
        theState = theServer->GetServerState();
    else
        theState = qtssStartingUpState;

    switch(inControlCode)
    {
    // Stop the service.
    //
    case SERVICE_CONTROL_STOP:
    case SERVICE_CONTROL_SHUTDOWN:
    {
        if (theState == qtssStartingUpState)
            break;

        //
        // Signal the server to shut down.
        theState = qtssShuttingDownState;
        if (theServer != NULL)
            theServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState));
        break;
    }
    case SERVICE_CONTROL_PAUSE:
    {
        if (theState != qtssRunningState)
            break;

        //
        // Signal the server to refuse new connections.
        theState = qtssRefusingConnectionsState;
        if (theServer != NULL)
            theServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState));
        break;
    }
    case SERVICE_CONTROL_CONTINUE:
    {
        if (theState != qtssRefusingConnectionsState)
            break;

        //
        // Signal the server to refuse new connections.
        theState = qtssRefusingConnectionsState;
        if (theServer != NULL)
            theServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState));
        break;
    }
    case SERVICE_CONTROL_INTERROGATE:
        break; // Just update our status

    default:
        break;
    }

    if (theServer != NULL)
    {
        theState = theServer->GetServerState();

        //
        // Convert a QTSS state to a Win32 Service state
        switch (theState)
        {
        case qtssStartingUpState:
            theStatusReport = SERVICE_START_PENDING;
            break;
        case qtssRunningState:
            theStatusReport = SERVICE_RUNNING;
            break;
        case qtssRefusingConnectionsState:
            theStatusReport = SERVICE_PAUSED;
            break;
        case qtssFatalErrorState:
            theStatusReport = SERVICE_STOP_PENDING;
            break;
        case qtssShuttingDownState:
            theStatusReport = SERVICE_STOP_PENDING;
            break;
        default:
            theStatusReport = SERVICE_RUNNING;
            break;
        }
    }
    else
        theStatusReport = SERVICE_START_PENDING;

    qtss_printf("Reporting status from ServiceControl function\n");
    ::ReportStatus(theStatusReport, NO_ERROR);
}
Пример #26
0
int main(int argc, char * argv[]) 
{
    extern char* optarg;
    
    //First thing to do is to read command-line arguments.
    int ch;
    
    char* theConfigFilePath = "./easydarwin.cfg";
    char* theXMLFilePath = "./easydarwin.xml";
    Bool16 notAService = false;
    Bool16 theXMLPrefsExist = true;
    Bool16 dontFork = false;
 
#if _DEBUG
    char* compileType = "Compile_Flags/_DEBUG; ";
#else
   char* compileType = "";
#endif

    while ((ch = getopt(argc,argv, "vdxp:o:c:irsS:I")) != EOF) // opt: means requires option
    {
        switch(ch)
        {
            case 'v':

                qtss_printf("%s/%s ( Build/%s; Platform/%s; %s%s) Built on: %s\n",QTSServerInterface::GetServerName().Ptr,
                                        QTSServerInterface::GetServerVersion().Ptr,
                                        QTSServerInterface::GetServerBuild().Ptr,
                                        QTSServerInterface::GetServerPlatform().Ptr,
                                        compileType,
                                        QTSServerInterface::GetServerComment().Ptr,
                                        QTSServerInterface::GetServerBuildDate().Ptr);

                qtss_printf("usage: %s [ -d | -p port | -v | -c /myconfigpath.xml | -o /myconfigpath.conf | -x | -S numseconds | -I | -h ]\n", QTSServerInterface::GetServerName().Ptr);
                qtss_printf("-d: Don't run as a Win32 Service\n");
                qtss_printf("-p XXX: Specify the default RTSP listening port of the server\n");
                qtss_printf("-c c:\\myconfigpath.xml: Specify a config file path\n");
                qtss_printf("-o c:\\myconfigpath.conf: Specify a DSS 1.x / 2.x config file path\n");
                qtss_printf("-x: Force create new .xml config file from 1.x / 2.x config\n");
                qtss_printf("-i: Install the Darwin Streaming Server service\n");
                qtss_printf("-r: Remove the Darwin Streaming Server service\n");
                qtss_printf("-s: Start the Darwin Streaming Server service\n");
                qtss_printf("-S n: Display server stats in the console every \"n\" seconds\n");
                qtss_printf("-I: Start the server in the idle state\n");
                ::exit(0);  
            case 'd':
                notAService = true;
                break;
            case 'p':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                sPort = ::atoi(optarg);
                break;
            case 'c':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                theXMLFilePath = optarg;
                break;
            case 'S':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                sStatsUpdateInterval = ::atoi(optarg);
                break;
            case 'o':
                Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt.
                theConfigFilePath = optarg;
                break;
            case 'x':
                theXMLPrefsExist = false; // Force us to generate a new XML prefs file
                break;
            case 'i':
                qtss_printf("Installing the Darwin Streaming Server service...\n");
                ::InstallService("Darwin Streaming Server");
                qtss_printf("Starting the Darwin Streaming Server service...\n");
                ::RunAsService("Darwin Streaming Server");
                ::exit(0);
                break;
            case 'r':
                qtss_printf("Removing the Darwin Streaming Server service...\n");
                ::RemoveService("Darwin Streaming Server");
                ::exit(0);
            case 's':
                qtss_printf("Starting the Darwin Streaming Server service...\n");
                ::RunAsService("Darwin Streaming Server");
                ::exit(0);
            case 'I':
                sInitialState = qtssIdleState;
                break;
            default:
                break;
        }
    }
    
    //
    // Check expiration date
    
    QTSSExpirationDate::PrintExpirationDate();
    if (QTSSExpirationDate::IsSoftwareExpired())
    {
        qtss_printf("Streaming Server has expired\n");
        ::exit(0);
    }

    //
    // Create an XML prefs parser object using the specified path
    sXMLParser = new XMLPrefsParser(theXMLFilePath);
    
    //
    // Check to see if the XML file exists as a directory. If it does,
    // just bail because we do not want to overwrite a directory
    if (sXMLParser->DoesFileExistAsDirectory())
    {
        qtss_printf("Directory located at location where streaming server prefs file should be.\n");
        ::exit(0);
    }
    
    if (!sXMLParser->CanWriteFile())
    {
        qtss_printf("Cannot write to the streaming server prefs file.\n");
        ::exit(0);
    }

    // If we aren't forced to create a new XML prefs file, whether
    // we do or not depends solely on whether the XML prefs file exists currently.
    if (theXMLPrefsExist)
        theXMLPrefsExist = sXMLParser->DoesFileExist();
    
    if (!theXMLPrefsExist)
    {
        //
        //Construct a Prefs Source object to get server preferences
        
        int prefsErr = sPrefsSource.InitFromConfigFile(theConfigFilePath);
        if ( prefsErr )
            qtss_printf("Could not load configuration file at %s.\n Generating a new prefs file at %s\n", theConfigFilePath, theXMLFilePath);

        //
        // Generate a brand-new XML prefs file out of the old prefs
        int xmlGenerateErr = GenerateAllXMLPrefs(&sPrefsSource, sXMLParser);
        if (xmlGenerateErr)
        {
            qtss_printf("Fatal Error: Could not create new prefs file at: %s. (%d)\n", theConfigFilePath, OSThread::GetErrno());
            ::exit(-1);
        }       
    }

    //
    // Parse the configs from the XML file
    int xmlParseErr = sXMLParser->Parse();
    if (xmlParseErr)
    {
        qtss_printf("Fatal Error: Could not load configuration file at %s. (%d)\n", theXMLFilePath, OSThread::GetErrno());
        ::exit(-1);
    }

    //
    // Construct a messages source object
    sMessagesSource.InitFromConfigFile("qtssmessages.txt");

    //
    // Start Win32 DLLs
    WORD wsVersion = MAKEWORD(1, 1);
    WSADATA wsData;
    (void)::WSAStartup(wsVersion, &wsData);
    
    if (notAService)
    {
        // If we're running off the command-line, don't do the service initiation crap.
        ::StartServer(sXMLParser, &sMessagesSource, sPort, sStatsUpdateInterval, sInitialState, false,0, kRunServerDebug_Off); // No stats update interval for now
        ::RunServer();
        ::exit(0);
    }
    
    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        { "", ServiceMain },
        { NULL, NULL }
    };

    //
    // In case someone runs the server improperly, print out a friendly message.
    qtss_printf("Darwin Streaming Server must either be started from the DOS Console\n");
    qtss_printf("using the -d command-line option, or using the Service Control Manager\n\n");
    qtss_printf("Waiting for the Service Control Manager to start Darwin Streaming Server...\n");
    BOOL theErr = ::StartServiceCtrlDispatcher(dispatchTable);
    if (!theErr)
    {
        qtss_printf("Fatal Error: Couldn't start Service\n");
        ::exit(-1);
    }

    return (0);
}
Пример #27
0
// this routine is not used
Bool16 RTPSessionOutput::PacketShouldBeThinned(QTSS_RTPStreamObject inStream, StrPtrLen* inPacket)
{
    return false; // function is disabled.
    
    static UInt16 sZero = 0;
    //This function determines whether the packet should be dropped.
    //It also adjusts the sequence number if necessary

    if (inPacket->Len < 4)
        return false;
    
    UInt16 curSeqNum = this->GetPacketSeqNumber(inPacket);
    UInt32* curQualityLevel = NULL;
    UInt16* nextSeqNum = NULL;
    UInt16* theSeqNumOffset = NULL;
    SInt64* lastChangeTime = NULL;
    
    UInt32 theLen = 0;
    (void)QTSS_GetValuePtr(inStream, qtssRTPStrQualityLevel, 0, (void**)&curQualityLevel, &theLen);
    if ((curQualityLevel == NULL) || (theLen != sizeof(UInt32)))
        return false;
    (void)QTSS_GetValuePtr(inStream, sNextSeqNumAttr, 0, (void**)&nextSeqNum, &theLen);
    if ((nextSeqNum == NULL) || (theLen != sizeof(UInt16)))
    {
        nextSeqNum = &sZero;
        (void)QTSS_SetValue(inStream, sNextSeqNumAttr, 0, nextSeqNum, sizeof(UInt16));
    }
    (void)QTSS_GetValuePtr(inStream, sSeqNumOffsetAttr, 0, (void**)&theSeqNumOffset, &theLen);
    if ((theSeqNumOffset == NULL) || (theLen != sizeof(UInt16)))
    {
        theSeqNumOffset = &sZero;
        (void)QTSS_SetValue(inStream, sSeqNumOffsetAttr, 0, theSeqNumOffset, sizeof(UInt16));
    }
    UInt16 newSeqNumOffset = *theSeqNumOffset;
    
    (void)QTSS_GetValuePtr(inStream, sLastQualityChangeAttr, 0, (void**)&lastChangeTime, &theLen);
    if ((lastChangeTime == NULL) || (theLen != sizeof(SInt64)))
    {   static SInt64 startTime = 0;
        lastChangeTime = &startTime;
        (void)QTSS_SetValue(inStream, sLastQualityChangeAttr, 0, lastChangeTime, sizeof(SInt64));
    }
    
    SInt64 timeNow = OS::Milliseconds();
    if (*lastChangeTime == 0 || *curQualityLevel == 0) 
        *lastChangeTime =timeNow;
    
    if (*curQualityLevel > 0 && ((*lastChangeTime + 30000) < timeNow) ) // 30 seconds between reductions
    {   *curQualityLevel -= 1; // reduce quality value.  If we quality doesn't change then we may have hit some steady state which we can't get out of without thinning or increasing the quality
        *lastChangeTime =timeNow; 
        //qtss_printf("RTPSessionOutput set quality to %"_U32BITARG_"\n",*curQualityLevel);
    }

    //Check to see if we need to drop to audio only
    if ((*curQualityLevel >= ReflectorSession::kAudioOnlyQuality) &&
        (*nextSeqNum == 0))
    {
#if REFLECTOR_THINNING_DEBUGGING || RTP_SESSION_DEBUGGING
        qtss_printf(" *** Reflector Dropping to audio only *** \n");
#endif
        //All we need to do in this case is mark the sequence number of the first dropped packet
        (void)QTSS_SetValue(inStream, sNextSeqNumAttr, 0, &curSeqNum, sizeof(UInt16));  
         *lastChangeTime =timeNow;  
    }
    
    
    //Check to see if we can reinstate video
    if ((*curQualityLevel == ReflectorSession::kNormalQuality) && (*nextSeqNum != 0))
    {
        //Compute the offset amount for each subsequent sequence number. This offset will
        //alter the sequence numbers so that they increment normally (providing the illusion to the
        //client that there are no missing packets)
        newSeqNumOffset = (*theSeqNumOffset) + (curSeqNum - (*nextSeqNum));
        (void)QTSS_SetValue(inStream, sSeqNumOffsetAttr, 0, &newSeqNumOffset, sizeof(UInt16));
        (void)QTSS_SetValue(inStream, sNextSeqNumAttr, 0, &sZero, sizeof(UInt16));
    }
    
    //tell the caller whether to drop this packet or not.
    if (*curQualityLevel >= ReflectorSession::kAudioOnlyQuality)
        return true;
    else
    {
        //Adjust the sequence number of the current packet based on the offset, if any
        curSeqNum -= newSeqNumOffset;
        this->SetPacketSeqNumber(inPacket, curSeqNum);
        return false;
    }
}
Пример #28
0
int main(int argc, char *argv[]) {
    // Temporary vars
    int             ch;
    UInt16          tempInt16;
    UInt32          tempInt32;
    Float32         tempFloat32;
    Float64         tempFloat64;

    // General vars
    int             fd;
    
    const char      *MovieFilename;
    int             TrackNumber;

    QTTrack         *Track;
    QTHintTrack     *HintTrack;
    bool            Debug = false, DeepDebug = false;
    
    UInt16          NumPackets;
    extern int optind;

    //
    // Read our command line options
    while( (ch = getopt(argc, argv, "dD")) != -1 ) {
        switch( ch ) {
            case 'd':
                Debug = true;
            break;

            case 'D':
                Debug = true;
                DeepDebug = true;
            break;
        }
    }

    argc -= optind;
    argv += optind;

    //
    // Validate our arguments.
    if( argc != 2 ) {
        qtss_printf("usage: QTRTPGen [-d] [-D] <filename> <track number>\n");
        exit(1);
    }
    
    MovieFilename = *argv++;
    TrackNumber = atoi(*argv++);


    //
    // Open the movie.
    QTFile file(Debug, DeepDebug);
    file.Open(MovieFilename);

    //
    // Find the specified track and dump out information about its' samples.
    if( !file.FindTrack(TrackNumber, &Track) ) {
        qtss_printf("Error!  Could not find track number %d in file \"%s\"!",
               TrackNumber, MovieFilename);
        exit(1);
    }
    
    //
    // Make sure that this is a hint track.
    if( !file.IsHintTrack(Track) ) {
        qtss_printf("Error!  Track number %d is not a hint track!\n", TrackNumber);
        exit(1);
    }
    HintTrack = (QTHintTrack *)Track;
    
    //
    // Initialize this track.
    HintTrack->Initialize();

    //
    // Dump some information about this track.
    {
        time_t      unixCreationTime = (time_t)HintTrack->GetCreationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
        time_t      unixModificationTime = (time_t)HintTrack->GetModificationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
        char        buffer[kTimeStrSize];
        struct tm  timeResult;
        
        qtss_printf("-- Track #%02"_S32BITARG_" ---------------------------\n", HintTrack->GetTrackID());
        qtss_printf("   Name               : %s\n", HintTrack->GetTrackName());
        qtss_printf("   Created on         : %s", qtss_asctime(qtss_gmtime(&unixCreationTime, &timeResult),buffer, sizeof(buffer)));
        qtss_printf("   Modified on        : %s", qtss_asctime(qtss_gmtime(&unixModificationTime, &timeResult),buffer, sizeof(buffer)));

        qtss_printf("   Total RTP bytes    : %"_64BITARG_"u\n", HintTrack->GetTotalRTPBytes());
        qtss_printf("   Total RTP packets  : %"_64BITARG_"u\n", HintTrack->GetTotalRTPPackets());
        qtss_printf("   Average bitrate    : %.2f Kbps\n",(float) ((HintTrack->GetTotalRTPBytes() << 3) / file.GetDurationInSeconds()) / 1024);
        qtss_printf("   Average packet size: %"_64BITARG_"u\n", HintTrack->GetTotalRTPBytes() / HintTrack->GetTotalRTPPackets());

        UInt32 UDPIPHeaderSize = (56 * HintTrack->GetTotalRTPPackets());
        UInt32 RTPUDPIPHeaderSize = ((56+12) * HintTrack->GetTotalRTPPackets());
        qtss_printf("   Percentage of stream wasted on UDP/IP headers    : %.2f\n", (float)UDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + UDPIPHeaderSize) * 100);
        qtss_printf("   Percentage of stream wasted on RTP/UDP/IP headers: %.2f\n", (float)RTPUDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + RTPUDPIPHeaderSize) * 100);
        qtss_printf("\n");
        qtss_printf("\n");
    }

    //
    // Open our file to write the packets out to.
    fd = open("track.cache", O_CREAT | O_TRUNC | O_WRONLY, 0666);
    if( fd == -1 ) {
        qtss_printf("Error!  Could not create output file!\n");
        exit(1);
    }
    
    //
    // Write out the header.
    tempInt16 = 1;
    write(fd, (char *)&tempInt16, 2);   // isCompletelyWritten
    tempInt16 = 0;
    write(fd, (char *)&tempInt16, 2);   // padding1
    tempFloat64 = file.GetDurationInSeconds();
    write(fd, (char *)&tempFloat64, 8); // movieLength
    tempInt32 = HintTrack->GetRTPTimescale();
    write(fd, (char *)&tempInt32, 4);   // rtpTimescale
    tempInt16 = HintTrack->GetRTPSequenceNumberRandomOffset();
    write(fd, (char *)&tempInt16, 2);   // seqNumRandomOffset
    tempInt16 = 0;
    write(fd, (char *)&tempInt16, 2);   // padding2
    tempFloat32 = HintTrack->GetTotalRTPBytes() / file.GetDurationInSeconds();
    write(fd, (char *)&tempFloat32, 4); // dataRate
    
    //
    // Go through all of the samples in this track, printing out their offsets
    // and sizes.
    qtss_printf("Sample #     NPkts\n");
    qtss_printf("--------     -----\n");
    UInt32 curSample = 1;
    QTHintTrack_HintTrackControlBlock HCB;
    while( HintTrack->GetNumPackets(curSample, &NumPackets) == QTTrack::errNoError ) {
        //
        // Generate all of the packets.
        qtss_printf("Generating %u packet(s) in sample #%"_U32BITARG_"..\n", NumPackets, curSample);
        for( UInt16 curPacket = 1; curPacket <= NumPackets; curPacket++ ) {
            // General vars
            #define MAX_PACKET_LEN 2048
            char        Packet[MAX_PACKET_LEN];
            UInt32      PacketLength;
            Float64     TransmitTime;
        
        
            //
            // Generate this packet.
            PacketLength = MAX_PACKET_LEN;
            HintTrack->GetPacket(curSample, curPacket,
                                 Packet, &PacketLength, 
                                 &TransmitTime, false, false, 0,&HCB);
            
            //
            // Write out the packet header.
            write(fd, (char *)&TransmitTime, 8);    // transmitTime
            tempInt16 = PacketLength;
            write(fd, (char *)&tempInt16, 2);       // packetLength
            tempInt16 = 0;
            write(fd, (char *)&tempInt16, 2);       // padding1
            
            //
            // Write out the packet.
            write(fd, Packet, PacketLength);
        }

        //
        // Next sample.
        curSample++;
    }
    
    //
    // Close the output file.
    close(fd);

    return 0;
}
Пример #29
0
QTSS_Error RTSPResponseStream::WriteV(iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength,
                                            UInt32* outLengthSent, UInt32 inSendType)
{
    QTSS_Error theErr = QTSS_NoErr;
    UInt32 theLengthSent = 0;
    UInt32 amtInBuffer = this->GetCurrentOffset() - fBytesSentInBuffer;
        
    if (amtInBuffer > 0)
    {

        // There is some data in the output buffer. Make sure to send that
        // first, using the empty space in the ioVec.
            
        inVec[0].iov_base = this->GetBufPtr() + fBytesSentInBuffer;
        inVec[0].iov_len = amtInBuffer;
        theErr = fSocket->WriteV(inVec, inNumVectors, &theLengthSent);
        
		if (fPrintRTSP)
		{
            DateBuffer theDate;
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time

 			qtss_printf("\n#S->C:\n#time: ms=%"_U32BITARG_" date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer() );
 			for (UInt32 i =0; i < inNumVectors; i++)
			{   StrPtrLen str((char*)inVec[i].iov_base, (UInt32) inVec[i].iov_len);
				str.PrintStrEOL();
  			}
 		}

        if (theLengthSent >= amtInBuffer)
        {
            // We were able to send all the data in the buffer. Great. Flush it.
            this->Reset();
            fBytesSentInBuffer = 0;
            
            // Make theLengthSent reflect the amount of data sent in the ioVec
            theLengthSent -= amtInBuffer;
        }
        else
        {
            // Uh oh. Not all the data in the buffer was sent. Update the
            // fBytesSentInBuffer count, and set theLengthSent to 0.
            
            fBytesSentInBuffer += theLengthSent;
            Assert(fBytesSentInBuffer < this->GetCurrentOffset());
            theLengthSent = 0;
        }
        // theLengthSent now represents how much data in the ioVec was sent
    }
    else if (inNumVectors > 1)
    {
        theErr = fSocket->WriteV(&inVec[1], inNumVectors - 1, &theLengthSent);
    }
    // We are supposed to refresh the timeout if there is a successful write.
    if (theErr == QTSS_NoErr)
        fTimeoutTask->RefreshTimeout();
        
    // If there was an error, don't alter anything, just bail
    if ((theErr != QTSS_NoErr) && (theErr != EAGAIN))
        return theErr;
    
    // theLengthSent at this point is the amount of data passed into
    // this function that was sent.
    if (outLengthSent != NULL)
        *outLengthSent = theLengthSent;

    // Update the StringFormatter fBytesWritten variable... this data
    // wasn't buffered in the output buffer at any time, so if we
    // don't do this, this amount would get lost
    fBytesWritten += theLengthSent;
    
    // All of the data was sent... whew!
    if (theLengthSent == inTotalLength)
        return QTSS_NoErr;
    
    // We need to determine now whether to copy the remaining unsent
    // iovec data into the buffer. This is determined based on
    // the inSendType parameter passed in.
    if (inSendType == kDontBuffer)
        return theErr;
    if ((inSendType == kAllOrNothing) && (theLengthSent == 0))
        return EAGAIN;
        
    // Some or none of the iovec data was sent. Copy the remainder into the output
    // buffer.
    
    // The caller should consider this data sent.
    if (outLengthSent != NULL)
        *outLengthSent = inTotalLength;
        
    UInt32 curVec = 1;
    while (theLengthSent >= inVec[curVec].iov_len)
    {
        // Skip over the vectors that were in fact sent.
        Assert(curVec < inNumVectors);
        theLengthSent -= inVec[curVec].iov_len;
        curVec++;
    }
    
    while (curVec < inNumVectors)
    {
        // Copy the remaining vectors into the buffer
        this->Put(  ((char*)inVec[curVec].iov_base) + theLengthSent,
                    inVec[curVec].iov_len - theLengthSent);
        theLengthSent = 0;
        curVec++;       
    }
    return QTSS_NoErr;
}
Пример #30
0
QTSS_Error EasyCMSSession::ProcessMessage()
{
	if(NULL == fRequest) return QTSS_BadArgument;

    //解析HTTPRequest报文
    QTSS_Error theErr = fRequest->Parse();
    if (theErr != QTSS_NoErr) return QTSS_BadArgument;

	//获取具体Content json数据部分
	StrPtrLen* lengthPtr = fRequest->GetHeaderValue(httpContentLengthHeader);
	StringParser theContentLenParser(lengthPtr);
    theContentLenParser.ConsumeWhitespace();
    UInt32 content_length = theContentLenParser.ConsumeInteger(NULL);

    if (content_length)
	{	
		qtss_printf("EasyCMSSession::ProcessMessage read content-length:%d \n", content_length);
		// 检查content的fContentBuffer和fContentBufferOffset是否有值存在,如果存在,说明我们已经开始
		// 进行content请求处理,如果不存在,我们需要创建并初始化fContentBuffer和fContentBufferOffset
		if (fContentBuffer == NULL)
		{
			fContentBuffer = NEW char[content_length + 1];
			memset(fContentBuffer,0,content_length + 1);
			fContentBufferOffset = 0;
		}
	    
		UInt32 theLen = 0;
		// 读取HTTP Content报文数据
		theErr = fInputStream.Read(fContentBuffer + fContentBufferOffset, content_length - fContentBufferOffset, &theLen);
		Assert(theErr != QTSS_BadArgument);

		if (theErr == QTSS_RequestFailed)
		{
			OSCharArrayDeleter charArrayPathDeleter(fContentBuffer);
			fContentBufferOffset = 0;
			fContentBuffer = NULL;

			return QTSS_RequestFailed;
		}
	    
		qtss_printf("EasyCMSSession::ProcessMessage() Add Len:%d \n", theLen);
		if ((theErr == QTSS_WouldBlock) || (theLen < ( content_length - fContentBufferOffset)))
		{
			//
			// Update our offset in the buffer
			fContentBufferOffset += theLen;
	       
			Assert(theErr == QTSS_NoErr);
			return QTSS_WouldBlock;
		}

		Assert(theErr == QTSS_NoErr);

	    // 处理完成报文后会自动进行Delete处理
		OSCharArrayDeleter charArrayPathDeleter(fContentBuffer);

		qtss_printf("EasyCMSSession::ProcessMessage() Get Complete Msg:\n%s", fContentBuffer);

		EasyProtocol protocol(fContentBuffer);
		int nNetMsg = protocol.GetMessageType();
		switch (nNetMsg)
		{
		case  MSG_SC_FREE_STREAM_ACK:
			{
				string strErrorNum		=	protocol.GetHeaderValue(EASY_TAG_ERROR_NUM);
				string strSerial		=	protocol.GetBodyValue(EASY_TAG_SERIAL);
				string strChannle		=	protocol.GetBodyValue(EASY_TAG_CHANNEL);
				
				qtss_printf("EasyCMS停止推流响应:%s,Serial=%s,Channel=%s",strErrorNum.c_str(),strSerial.c_str(),strChannle.c_str());
				fLiveSession=false;//进入析构
			}
			break;
		default:
			break;
		}
	}