SemiProxySession Class Reference

This class is used to handle a single rtsp-session. More...

#include <SemiProxySession.hpp>

Inheritance diagram for SemiProxySession:

Session VThread List of all members.

Public Member Functions

 SemiProxySession (int fdclient, struct sockaddr_in *clientsock, SemiProxy *sp)
 default constructor
 ~SemiProxySession ()
 default destructor
void run ()
 Reads messages from client and server until the end of this session.
void parseResponseFromServer (char *buffer, int len)
 This function parses the response from the server.
void forwardToServer (char *buffer, int len)
 This function forwards a message to the server.
void forwardToClient (char *buffer, int len)
 Forwards a message to the client.
void handleOptionsResponse (string &buf, int &bytesRead)
 Handles the OPTIONS-response from the server.
void handleDescribeResponse (string &buf, int &bytesRead)
 Handles the DESCRIBE-response from the server.
void handleSetupResponse (string &buf, int &bytesRead)
 Handles the SETUP-response from the server.
void handlePlayResponse (string &buf, int &bytesRead)
 Handles the PLAY-response from the server.
void handlePauseResponse (string &buf, int &bytesRead)
 Handles the PAUSE-response from the server.
void handleTeardownResponse (string &buf, int &bytesRead)
 Handles the TEARDOWN-response from the server.
bool getOptions (const Url *fileName, const char *remaining)
 Handles a GET_PARAMETER message, sent from the client.
bool setOptions (const Url *fileName, const char *remaining)
 Handles a SET_PARAMETER message, sent from the client.
bool options (const Url *fileName, const char *remaining)
 Parses a OPTIONS message and forwards it to the server.
bool connect (const Url *fileName, const char *remaining)
 Parses a DESCRIBE message and forwards it to the server.
bool setup (const Url *fileName, const char *remaining)
 Parses a SETUP message and forwards it to the server.
bool play (const Url *fileName, const char *remaining)
 Parses a PLAY message and forwards it to the server.
bool pause (const Url *fileName, const char *remaining)
 Handles a PAUSE message, sent from the client.
bool tearDown (int sessionKey, bool immediate=false, const Url *fileName=NULL, const char *remaining=NULL)
 Handles a TEARDOWN message, sent from the client.
bool containsSessionID (uint SessionID)
 Look if specified SessionID is contained in any track of this session.
uint getServerTimeMs ()
 Retrieve current 'client playout time' of this session from server.
uint getClientTimeMs ()
 Retrieve current 'client playout time' of this session from client.
void testClientOptions ()
uint requestServerTimeMs ()
 Initiate request of current 'client playout time' of this session on next main-loop run from the serrver.
uint requestClientTimeMs ()
 Initiate request of current 'client playout time' of this session on next main-loop run from the client.
void sendTeardownToClient ()
 Send a Rtsp-TEARDOWN to the client.
void closeSession ()
 Close the current session (by closing the socket to client and server) Furthermore, the SSession object is marked as 'closed'.
void removeSession ()
 Close the current session (by closing the socket to client and server) Furthermore, the SSession object is removed from the sessionlist.
void setUrl (const Url *uri, bool makeExactMatch=true)
 Empty method which is created for conformance to Session.cpp.
void setStateClosed ()
 Set the session state.
PlayerInformation getPlayerInfo ()

Static Public Member Functions

SemiProxySessiongetSemiProxySession (uint RtspSessionId)
 Return the reference to a particular session from the static vector of this class.

Detailed Description

This class is used to handle a single rtsp-session.

It contains the most functionality of the semiproxy application.

Author:
Klaus Schoeffmann

Definition at line 97 of file SemiProxySession.hpp.


Member Function Documentation

void SemiProxySession::forwardToClient char *  buffer,
int  len
 

Forwards a message to the client.

Also replaces the CSeq value, set by the server to the stored CSeq value received from the client! Definition at line 588 of file SemiProxySession.cpp.

References getClientTimeMs(), URIParameters::getFullURI(), URIParameters::getHost(), getPlayerInfo(), URIParameters::getPort(), getSemiProxySession(), semifunc::replaceStr(), TimeMeasurement::setTSclientPlayout(), SemiProxy::shouldRequestClientPosition(), and TimeMeasurement::startTS().

Referenced by handleDescribeResponse(), handleOptionsResponse(), handlePauseResponse(), handlePlayResponse(), handleSetupResponse(), and handleTeardownResponse().

00589 { 00590 Globals::sdebug << "\n::forwardToClient(): starts"; 00591 if (buffer == NULL) 00592 { 00593 Globals::sdebug << "\n::forwardToClient(): detected buffer=NULL!!!"; 00594 } 00595 else 00596 { 00597 00598 //first store CSeq received from server 00599 extractCSeq(buffer, lastServerCSeq); 00600 Globals::sdebug << "\n::forwardToClient(): lastServerCSeq=" << lastServerCSeq; 00601 00602 string str(buffer); 00603 00604 //if the client uses a host/port parameter (because it doesn't support a proxy), 00605 //replace the content-base to the original filename 00606 if ((params.getFullURI() != NULL) && ((params.getHost() != NULL) || (params.getPort() != 0)) ) 00607 { 00608 uint cbstart = str.find("Content-Base: "); 00609 if (cbstart != string::npos) 00610 { 00611 uint cbend = str.find("\r\n", cbstart); 00612 std::ostringstream newContentBase; 00613 newContentBase << "Content-Base: " << params.getFullURI(); 00614 semifunc::replaceStr(str, cbstart, cbend, (char*)newContentBase.str().c_str()); 00615 } 00616 } 00617 00618 //replace CSeq value 00619 replaceCSeq(str, lastClientCSeq); 00620 00621 //debugging output 00622 string tmpstr (str); 00623 semifunc::replaceStr(tmpstr, "\r\n", "\r \n\t", true); 00624 Globals::sdebug << "\n::forwardToClient(): Forwarding to CLIENT:\n" << tmpstr; 00625 00626 send(this->fdclient, str.c_str(), str.length(), 0); 00627 00628 //if last client message was PLAY, start time-measurement for current time-section 00629 //but only for the _first_ PLAY message (session-state not ACTIVE) 00630 if (this->lastClientRtspMsg == RTSP_PLAY && state != SESSION_ACTIVE) 00631 { 00632 Globals::sdebug << "\n::forwardToClient(): _time measurement started_"; 00633 timemsmnt->startTS(); 00634 } else { 00635 Globals::sdebug << "\n::forwardToClient(): _time measureemnt not started (" << lastClientRtspMsg << "==" << RTSP_PLAY << ", " << state << "!=" << SESSION_ACTIVE << ")"; 00636 } 00637 00638 //request current media time from media player 00639 //but only for the _first_ PAUSE message (if there are more than on track) 00640 if (this->lastClientRtspMsg == RTSP_PAUSE && sp->shouldRequestClientPosition() && state != SESSION_PAUSED 00641 && SemiProxySession::getSemiProxySession(this->RtspSessionID)->getPlayerInfo() != PI_PVPLAYER) 00642 { 00643 ulong cplayout = SemiProxySession::getSemiProxySession(this->RtspSessionID)->getClientTimeMs(); 00644 timemsmnt->setTSclientPlayout(cplayout); 00645 } 00646 00647 Globals::sdebug << "\n::forwardToClient(): success"; 00648 } 00649 }

void SemiProxySession::forwardToServer char *  buffer,
int  len
 

This function forwards a message to the server.

It also looks for parameters specified in the RTSP-URI and removes it. If message-type is DESCRIBE and a profile-ID was specified, also the TerminalCapabilites (of the specified profile) will be added. Furthermore, this function stores the received CSeq value from the client. Definition at line 482 of file SemiProxySession.cpp.

References URIParameters::getHost(), URIParameters::getPort(), ProfileList::getProfileById(), URIParameters::getProfileId(), SemiProxy::getProfileList(), and SemiProxy::shouldAddTermCaps().

Referenced by connect(), getOptions(), options(), pause(), play(), setOptions(), setup(), and tearDown().

00483 { 00484 Globals::sdebug << "\n::forwardToServer(): starts"; 00485 if (buffer == NULL) 00486 { 00487 Globals::sdebug << "\n::forwardToServer(): detected buffer=NULL!!!"; 00488 } 00489 else 00490 { 00491 00492 //first store CSeq received from client 00493 Globals::sdebug << "\n::forwardToServer(): before call to extractCSeq()"; 00494 extractCSeq(buffer, lastClientCSeq); 00495 Globals::sdebug << "\n::forwardToServer(): lastClientCSeq=" << lastClientCSeq; 00496 00497 //additional newlines, needed for pvplayer 00498 string strbuf(buffer); 00499 if (params.getPort() > 0 || params.getHost() != NULL) { 00500 strbuf.append("\r\n\r\n"); 00501 } 00502 00503 00504 //add/change terminal capabilites? 00505 if (sp->shouldAddTermCaps()) 00506 { 00507 00508 //check terminal capabilities (only if profile specified) 00509 if (lastClientRtspMsg == RTSP_DESCRIBE && params.getProfileId() != 0) 00510 { 00511 uint tcBegin, tcEnd; 00512 00513 Profile *profile = sp->getProfileList()->getProfileById(params.getProfileId()); 00514 assert(profile != NULL); 00515 string termCaps = createTerminalCapabilities(profile); 00516 00517 tcBegin = strbuf.find("<xml "); 00518 tcEnd = strbuf.find("</DIDL>"); 00519 00520 if (strbuf.find("Content-Type: application/mpeg21_dia") != string::npos && 00521 tcBegin != string::npos && tcEnd != string::npos) 00522 { 00523 00524 //termcaps found 00525 strbuf.replace(tcBegin, (tcEnd + 7) - tcBegin, termCaps); 00526 uint currentLength = getContentLength(strbuf); 00527 currentLength -= (tcEnd + 7) - tcBegin; 00528 currentLength += termCaps.length(); 00529 //correct content-length 00530 changeContentLength(strbuf, currentLength); 00531 00532 } 00533 else 00534 { 00535 00536 noTermCapsFound = true; 00537 00538 Globals::sdebug << "\n::forwardToServer(): No Terminalcapabilities found... will add!"; 00539 00540 if (strbuf.find("Content-Length:") != string::npos) 00541 { 00542 cerr << "\n::forwardToServer(): cannot handle existing DESCRIBE content!" << endl; 00543 } 00544 else 00545 { 00546 00547 ostringstream ctinfo, content; 00548 ctinfo << "Content-Type: application/mpeg21_dia\r\n" 00549 << "Content-Length: " << termCaps.length() << "\r\n\r\n" 00550 << termCaps << "\r\n"; 00551 00552 uint uapos1, uapos2; 00553 if ((uapos1 = strbuf.find("User-Agent:")) != string::npos) 00554 { 00555 uapos2 = strbuf.find("\r\n", uapos1); 00556 strbuf.insert(uapos2+2, ctinfo.str()); 00557 00558 //append tercaps to end 00559 strbuf.insert(strbuf.rend()-strbuf.rbegin(), content.str()); 00560 } 00561 else 00562 { 00563 cerr << "\n::forwardToServer(): User-Agent not found in message!" << endl; 00564 } 00565 00566 } 00567 00568 } 00569 } 00570 } 00571 00572 00573 //replace CSeq value 00574 replaceCSeq(strbuf, lastServerCSeq+1); 00575 00576 //debugging output 00577 string tmpstr(strbuf); 00578 Globals::sdebug << "\n::forwardToServer(): Forwarding to SERVER:\n" << tmpstr; 00579 00580 send(this->fdserver, strbuf.c_str(), strbuf.length(), 0); 00581 00582 Globals::sdebug << "\n::forwardToServer(): success"; 00583 } 00584 }

void SemiProxySession::parseResponseFromServer char *  buffer,
int  len
 

This function parses the response from the server.

Depending on this response, this function either

  • creates a new SSession (on successful response to a play-message)
  • sets the SSession to state 'active' again (when the response was the ok for a subsequent play-message)
Definition at line 794 of file SemiProxySession.cpp.

References URIParameters::getMovieId(), URIParameters::getProfileId(), URIParameters::getUserId(), handleDescribeResponse(), handleOptionsResponse(), handlePauseResponse(), handlePlayResponse(), handleSetupResponse(), and handleTeardownResponse().

Referenced by run().

00795 { 00796 assert(buffer); 00797 00798 Globals::sdebug << "\n::parseResponseFromServer(): starts"; 00799 00800 //only parse response, if all necessary params were passed from the client 00801 if (params.getMovieId() != NULL && params.getUserId() != 0 && params.getProfileId() != 0) 00802 { 00803 00804 string buf (buffer); 00805 00806 //look if RTSP 200 OK is contained in the message 00807 if (buf.find("200") != string::npos && buf.find("OK") != string::npos) 00808 { 00809 switch(lastClientRtspMsg) 00810 { 00811 case RTSP_OPTIONS: 00812 handleOptionsResponse(buf, len); 00813 break; 00814 case RTSP_DESCRIBE: 00815 handleDescribeResponse(buf, len); 00816 break; 00817 case RTSP_SETUP: 00818 handleSetupResponse(buf, len); 00819 break; 00820 case RTSP_PLAY: 00821 handlePlayResponse(buf, len); 00822 break; 00823 case RTSP_PAUSE: 00824 handlePauseResponse(buf, len); 00825 break; 00826 case RTSP_TEARDOWN: 00827 handleTeardownResponse(buf, len); 00828 break; 00829 } 00830 } 00831 00832 } 00833 else 00834 { 00835 Globals::sdebug << "\n::parseResponseFromServer(): IGNORED (not all params found!)"; 00836 cerr << "\n::parseResponseFromServer(): IGNORED (not all params found!)"; 00837 } 00838 00839 Globals::sdebug << "\n::parseResponseFromServer(): ends"; 00840 }

bool SemiProxySession::play const Url fileName,
const char *  remaining
[virtual]
 

Parses a PLAY message and forwards it to the server.

If the URI of this message contains an existing RTSP-Session-ID (which means, this session should take over the other session), the Range- Parameter of this message will be replaced by the current time of the other session. This function also extracts the RTSP-SessionId of the message.

Implements Session.

Definition at line 948 of file SemiProxySession.cpp.

References TimeMeasurement::addNewSection(), RTSP::extractSessionKeyFromCMD(), forwardToServer(), Profile::getBufferingDelayms(), SSession::getElapsedMsecs(), getPlayerInfo(), SSession::getPreviousSessionDuration(), ProfileList::getProfileById(), URIParameters::getProfileId(), SemiProxy::getProfileList(), URIParameters::getRange(), URIParameters::getSection(), getSemiProxySession(), SemiProxy::getSession(), URIParameters::getSessionId(), SSession::getState(), URIParameters::getSubtractSecs(), TrackList::getTCHavingState(), requestClientTimeMs(), requestServerTimeMs(), TimeMeasurement::setTSrequestedFrom(), SemiProxy::shouldRequestClientPosition(), SemiProxy::shouldRequestServerPosition(), and Url::toString().

00949 { 00950 assert(remaining); assert(fileName); 00951 Globals::sdebug << "\n::play(): starts"; 00952 lastClientRtspMsg = RTSP_PLAY; 00953 00954 string strbuf (buffer); 00955 00956 //extract prebuffer-time 00957 ulong prebuffer = extractPrebuffer(strbuf); 00958 if (prebuffer == 0 && params.getProfileId() != 0) 00959 { 00960 //if no prebuffer-time was specified by the player, use prebuffer-time from profile 00961 prebuffer = sp->getProfileList()->getProfileById(params.getProfileId())->getBufferingDelayms(); 00962 } 00963 Globals::sdebug << "\n::play(): prebuffer=" << prebuffer; 00964 00965 //on known protocol: extract RTSP-SessionId and URI 00966 if (prot) 00967 { 00968 lastCRtspSessionID = prot->extractSessionKeyFromCMD(remaining); 00969 //extract sessionID and URI only for first track 00970 if (tracks.getTCHavingState(TRACK_ACTIVE) == 0) { 00971 RtspSessionID = lastCRtspSessionID;//prot->extractSessionKeyFromCMD(remaining); 00972 SessionURI = new char[strlen(fileName->toString())+1]; 00973 strcpy(SessionURI, fileName->toString()); 00974 } 00975 } else { 00976 Globals::sdebug << "\n::play(): prot IS NULL !!!"; 00977 } 00978 00979 //for consecutive play (resumes): 00980 //if this session is a migrated session, add elapsed time of 00981 //original session to the range, requested by the client 00982 //(otherwise, some players would start from wrong position) 00983 if (sessionHasBeenPaused) 00984 { 00985 Globals::sdebug << "\n::play(): consecutive play"; 00986 00987 if (asess->getPreviousSessionDuration() != 0) 00988 { 00989 Globals::sdebug << "\n::play(): prevDur= " << asess->getPreviousSessionDuration(); 00990 replaceRange(strbuf, semifunc::convertToString(extractRangeFrom(strbuf)+asess->getPreviousSessionDuration())); 00991 } 00992 00993 } 00994 00995 00996 if (state != SESSION_ACTIVE && tracks.getTCHavingState(TRACK_ACTIVE) == 0) 00997 { 00998 assert(timemsmnt != NULL); 00999 //create new time-section on time-measurement 01000 timemsmnt->addNewSection(prebuffer); 01001 //set requested range-from value 01002 timemsmnt->setTSrequestedFrom(extractRangeFrom(strbuf)); 01003 } 01004 01005 01006 //check if this session should take over another session 01007 //do not migrate a migrated session again (which is only paused and resumed!) 01008 //moreover, do not migrate a session if the PLAY message for the second track was received 01009 if (params.getSessionId() != 0 && tracks.getTCHavingState(TRACK_ACTIVE) == 0) 01010 { 01011 01012 //session, which should be taken over must exist! 01013 SSession *otherSession = sp->getSession(params.getSessionId()); 01014 if (otherSession != NULL) 01015 { 01016 01017 //get time OF OTHER SESSION 01018 01019 ulong splayout = 0, cplayout = 0; 01020 01021 01022 //should request mediatime from client? 01023 Globals::sdebug << "\n::play() requesting position from client?"; 01024 if (sp->shouldRequestClientPosition() && otherSession && otherSession->getState() != STATE_CLOSED 01025 && SemiProxySession::getSemiProxySession(params.getSessionId())->getPlayerInfo() != PI_PVPLAYER) 01026 { 01027 //get client-playout time for other session from server 01028 assert(SemiProxySession::getSemiProxySession(params.getSessionId()) != NULL); 01029 cplayout = SemiProxySession::getSemiProxySession(params.getSessionId())->requestClientTimeMs(); 01030 01031 Globals::sdebug << "\n::play(" << RtspSessionID << "): client playout of other session= " << cplayout; 01032 } 01033 01034 if (cplayout == 0) 01035 { 01036 Globals::sdebug << "\n::play(): NO REQUEST FROM CLIENT, try server"; 01037 01038 //should request mediatime from server? 01039 if (sp->shouldRequestServerPosition() 01040 && otherSession && otherSession->getState() != STATE_CLOSED) 01041 { 01042 //get client-playout time for other session from server 01043 assert(SemiProxySession::getSemiProxySession(params.getSessionId()) != NULL); 01044 splayout = SemiProxySession::getSemiProxySession(params.getSessionId())->requestServerTimeMs(); 01045 01046 Globals::sdebug << "\n::play(" << RtspSessionID << "): server playout of other session= " << splayout; 01047 } 01048 else 01049 { 01050 Globals::sdebug << "\n::play(): NO REQUEST FROM SERVER, use own estimation"; 01051 } 01052 } 01053 01054 01055 //calculate position (correct value from server or user own estimation) 01056 ulong msecsOS = sp->getSession(params.getSessionId())->getElapsedMsecs(params.getSection(), splayout, cplayout); 01057 Globals::sdebug << "\n::play(): msecs of other session= " << msecsOS; 01058 01059 //add/subtract the specified number of seconds (if specified) 01060 if (msecsOS >= (uint)(params.getSubtractSecs() * 1000)) 01061 { 01062 msecsOS -= params.getSubtractSecs() * 1000; 01063 } 01064 01065 Globals::sdebug << "\n::play(): msecs of other session after subtract(" 01066 << params.getSubtractSecs() * 1000 << ") = " << msecsOS; 01067 01068 //store time of old session in variable 'elapsedTimeMsecs' for NEW SESSION 01069 //(will be used on creation of SSession) 01070 //prevDuration = msecsOS + startupOffset; 01071 prevDuration = msecsOS; 01072 01073 //convert time to string and replace range-parameter in the message 01074 replaceRange(strbuf, semifunc::convertToString(msecsOS)); 01075 01076 } 01077 } else if (params.getSessionId() != 0) { 01078 replaceRange(strbuf, semifunc::convertToString(prevDuration)); 01079 } 01080 01081 01082 //check if an explicit range parameter were specified 01083 if (params.getRange() != NULL) 01084 { 01085 //if so, replace the previous range 01086 replaceRange(strbuf, params.getRange(), false); 01087 } 01088 01089 forwardToServer((char*)strbuf.c_str(), strbuf.length()); 01090 01091 return true; 01092 }

void SemiProxySession::run  )  [virtual]
 

Reads messages from client and server until the end of this session.

The messages will be parsed and forwarded to the opponent.

Implements VThread.

Definition at line 1630 of file SemiProxySession.cpp.

References RTSP::applyReqToSession(), closeSession(), Session::determineProtocol(), getClientTimeMs(), Protocol::getID(), getServerTimeMs(), parseResponseFromServer(), removeSession(), URIParameters::setAction(), URIParameters::setFullURI(), URIParameters::setHost(), URIParameters::setMovieId(), URIParameters::setPort(), URIParameters::setProfileId(), URIParameters::setRange(), URIParameters::setSection(), URIParameters::setSessionId(), URIParameters::setSubtractSecs(), URIParameters::setUserId(), TimeMeasurement::stopTS(), and tearDown().

01631 { 01632 01633 fd_set rfds; 01634 struct timeval tv; 01635 01636 //number of microseconds to sleep after a loop run 01637 ulong sleep_msecs = PROXY_SLEEP_USECS; 01638 01639 int bytesReadClient = -1; 01640 int bytesReadServer = -1; 01641 01642 //pointer to begin of buffer 01643 char *bufferstart = buffer; 01644 01645 01646 while (state!=SESSION_ERR && state!=SESSION_CLOSED) 01647 { 01648 //first check if socket has closed 01649 if (fdclient == 0) 01650 { 01651 Globals::sdebug << "\n::run(): Client has closed socket -> CLOSE SESSION"; 01652 closeSession(); 01653 break; 01654 } 01655 01656 //(maximum) waiting time for select 01657 tv.tv_sec = 0; 01658 tv.tv_usec = 10000; 01659 01660 FD_ZERO(&rfds); 01661 //only add client or server to FD_LIST, when socket has not been closed! 01662 if (bytesReadClient != 0) FD_SET(fdclient, &rfds); 01663 if (bytesReadServer != 0) FD_SET(fdserver, &rfds); 01664 //use bigger socket-number for select 01665 int maxsocknr = (fdclient < fdserver) ? fdserver : fdclient; 01666 int retval = select(maxsocknr+1, &rfds, NULL, NULL, &tv); 01667 if (retval == -1) 01668 { 01669 cerr << "\nSPS::run(): ERROR select()" << endl; 01670 } 01671 else if (retval) 01672 { 01673 01674 //************************READ FROM CLIENT start************************* 01675 if (FD_ISSET(fdclient, &rfds)) 01676 { 01677 sessionControlChannel = fdclient; 01678 01679 buffer = bufferstart; 01680 memset(buffer, 0, MSG_BUFFER_SIZE); 01681 01682 01683 //read until no more bytes (because of MTU) 01684 readFromSocket(fdclient, tv, rfds); 01685 bytesReadClient = bytesRead; 01686 01687 01688 //**readRequest does not correctly work with other players !!!** 01689 //bytesReadClient = bytesRead = readRequest(buffer, MSG_BUFFER_SIZE); 01690 01691 //on PAUSE stop time-measurement 01692 if (strstr(buffer, "PAUSE rtsp://") != NULL) 01693 { 01694 //stop time-measurement for current time-section 01695 timemsmnt->stopTS(); 01696 } 01697 01698 01699 //special handling for quicktime embedded 01700 //(TODO:CAN BE REMOVED, IF applyReqToSession can handle several callbacks) 01701 char *teardownstart; 01702 if (strncmp(buffer, "PAUSE", 5) == 0 01703 && (teardownstart = strstr(buffer, "TEARDOWN")) != NULL) 01704 { 01705 //remove pause 01706 bytesReadClient = bytesRead = bytesRead - (teardownstart - buffer); 01707 buffer = teardownstart; 01708 } 01709 char *playstart; 01710 if (strncmp(buffer, "SET_PARAMETER", 13) == 0 01711 && (playstart = strstr(buffer, "PLAY")) != NULL) 01712 { 01713 bytesReadClient = bytesRead = bytesRead - (playstart - buffer); 01714 //remove set_parameter 01715 buffer = playstart; 01716 } 01717 01718 01719 //on DESCRIBE extract full-URI 01720 if (strstr(buffer, "DESCRIBE rtsp://") != NULL) 01721 { 01722 char *fnstart, *fnend; 01723 if ((fnstart = strstr(buffer, "rtsp://")) != NULL) 01724 { 01725 if ((fnend = strstr(fnstart, " ")) != NULL) 01726 { 01727 params.setFullURI(semifunc::newStrCpy(fnstart, fnend-fnstart)); 01728 } 01729 } 01730 } 01731 01732 01733 //new extract (and remove!) ALL PARAMETERS 01734 string bufferstr (buffer); 01735 01736 01737 //look for parameters in the URI and remove them 01738 char *pmovieid, *prange, *phost; 01739 int puid, pproid, psid, pport, action, section, subtractMsecs; 01740 if ((puid = extractParameter(bufferstr, "/uid=", true)) >= 0) 01741 { 01742 params.setUserId(puid); 01743 } 01744 if ((pproid = extractParameter(bufferstr, "/proid=", true)) >= 0) 01745 { 01746 params.setProfileId(pproid); 01747 } 01748 if ((pmovieid = extractStrParameter(bufferstr, "/id=", true)) != NULL) 01749 { 01750 params.setMovieId(pmovieid); 01751 } 01752 if ((psid = extractParameter(bufferstr, "/sid=", true)) >= 0) 01753 { 01754 params.setSessionId(psid); 01755 } 01756 if ((action = extractParameter(bufferstr, "/action=", true)) >= 0) 01757 { 01758 params.setAction(action); 01759 } 01760 if ((section = extractParameter(bufferstr, "/section=", true)) >= 0) 01761 { 01762 params.setSection(section); 01763 } 01764 if ((subtractMsecs = extractParameter(bufferstr, "/sub=", true)) >= 0) 01765 { 01766 params.setSubtractSecs(subtractMsecs); 01767 } 01768 //special parameters (if no RTSP proxy can be used!) 01769 if ((prange =extractStrParameter(bufferstr, "/range=",true)) != NULL) 01770 { 01771 params.setRange(prange); 01772 } 01773 if ((phost = extractStrParameter(bufferstr, "/host=", true)) != NULL) 01774 { 01775 params.setHost(phost); 01776 } 01777 if ((pport = extractParameter(bufferstr, "/port=", true)) >= 0) 01778 { 01779 params.setPort(pport); 01780 } 01781 01782 //store back buffer (with params removed) 01783 buffer = bufferstart; 01784 memset(buffer, 0, MSG_BUFFER_SIZE); 01785 bufferstr.copy(buffer, bufferstr.length()); 01786 //buffer = (char*)bufferstr.c_str(); 01787 01788 01789 //check hostname and port (cannot be same as host+port of proxy) 01790 //NOTE: this function may change the address and port of the request!!! 01791 if (checkForValidAddress(buffer, bytesRead)) 01792 { 01793 01794 Globals::sdebug << "\nSP::run(): received from client:\n\t" << buffer; 01795 01796 if (bytesRead == 0) 01797 { 01798 //no data read; the other side has closed the connection, teardown all 01799 tearDown(TEARDOWN_ALL,true, NULL, NULL); 01800 } 01801 else if (bytesRead < 0) 01802 { 01803 cerr << "\nSPS::run(): Error reading from controlchannel" << endl; 01804 tearDown(TEARDOWN_ALL,true,NULL, NULL); 01805 state = SESSION_ERR; 01806 } 01807 else 01808 { 01809 // we have got a command from the client; parse it and forward it to the server 01810 01811 //determine protocol of message 01812 if (!prot) 01813 { 01814 if ( determineProtocol(buffer) == PROTO_UNKNOWN) 01815 { 01816 cerr << "\nSPS::run(): Unknown protocol: " << buffer << endl; 01817 } 01818 } 01819 01820 //if known protocol was recognized, perform further parsing... 01821 if (prot) 01822 { 01823 switch (prot->getID()) 01824 { 01825 case PROTO_RTSP: 01826 if (bytesRead >= MSG_BUFFER_SIZE) 01827 { 01828 cerr << "\nSPS::run(): received command exceeded buffer size" << endl; 01829 break; 01830 } 01831 break; 01832 default: 01833 cerr << "\nSPS::run(): Unknown protocol: " << buffer << endl; 01834 break; 01835 } 01836 01837 //call control-function in RTSP-object; this function will callback other functions 01838 //in this object like connect(), setup(), play(), pause(), teardown()... 01839 if (!prot->applyReqToSession(buffer, bytesRead, this, true)) 01840 { 01841 cerr << "\nSPS::run(): Failed to parse request '" << buffer << "'" << endl; 01842 } 01843 01844 } 01845 } 01846 } 01847 } 01848 //************************read from client end************************* 01849 01850 01851 01852 //************************READ FROM SERVER start************************* 01853 if (FD_ISSET(fdserver, &rfds)) 01854 { 01855 sessionControlChannel = fdserver; 01856 01857 buffer = bufferstart; 01858 memset(buffer, 0, MSG_BUFFER_SIZE); 01859 //use common receive-function, because readRequest do not 01860 //work sometimes (doesn't call options/setup/... functions) 01861 01862 //read until no more bytes (because of MTU) 01863 readFromSocket(fdserver, tv, rfds); 01864 bytesReadServer = bytesRead; 01865 //bytesReadServer = bytesRead = recv(fdserver, buffer, MSG_BUFFER_SIZE, 0); 01866 //bytesReadServer = bytesRead = readRequest(buffer, MSG_BUFFER_SIZE); 01867 01868 Globals::sdebug << "\nSP::run(): received from server (" << bytesReadServer << " bytes):\n\t" << buffer; 01869 01870 if (bytesRead == 0) 01871 { 01872 //no data read; the server has closed the connection, teardown all 01873 cerr << "\nSPS::run(): No data read from ControlChannel (SERVER has closed connection)" << endl; 01874 removeSession(); 01875 } 01876 else if (bytesRead < 0) 01877 { 01878 cerr << "\nSPS::run(): Error reading from controlchannel" << endl; 01879 removeSession(); 01880 } 01881 else 01882 { 01883 // we got a command from the server; parse it and forward to client 01884 parseResponseFromServer(buffer, bytesRead); 01885 } 01886 } 01887 //************************read from server end************************* 01888 } 01889 01890 //look if there is an outstanding position-request 01891 //this special handling is necessary, because otherwise (if another session directly 01892 //calls 'getServerTimeMs()') the response could be received in this main-loop as 01893 //instead of the recv() of 'getServerTimeMs()'. This is because concurrent execution 01894 if (state != SESSION_ERR && state != SESSION_CLOSED) { 01895 if (sendServerPositionRequest == true) 01896 { 01897 Globals::sdebug << "\n::run(" << RtspSessionID << "): outstanding server position request - STARTS"; 01898 receivedServerPosition = this->getServerTimeMs(); 01899 sendServerPositionRequest = false; 01900 Globals::sdebug << "\n::run(" << RtspSessionID << "): outstanding server position request - DONE"; 01901 } 01902 01903 else if (sendClientPositionRequest == true) 01904 { 01905 Globals::sdebug << "\n::run(" << RtspSessionID << "): outstanding client position request - STARTS"; 01906 receivedClientPosition = this->getClientTimeMs(); 01907 sendClientPositionRequest = false; 01908 Globals::sdebug << "\n::run(" << RtspSessionID << "): outstanding client position request - DONE"; 01909 } 01910 01911 #ifndef WIN32 01912 usleep(sleep_msecs); 01913 #else 01914 Sleep(sleep_msecs); 01915 #endif 01916 } 01917 01918 } 01919 01920 Globals::sdebug << "::run() closing SemiProxySession " << RtspSessionID << "\n"; 01921 }

bool SemiProxySession::setup const Url fileName,
const char *  remaining
[virtual]
 

Parses a SETUP message and forwards it to the server.

Also inserts a destination parameter, which is set to the address of the client that sent this message, into the the message.

Implements Session.

Definition at line 901 of file SemiProxySession.cpp.

References TrackList::addTrack(), forwardToServer(), and SemiProxy::shouldAddDestination().

00902 { 00903 assert(remaining); assert(fileName); 00904 Globals::sdebug << "\n::setup(): starts"; 00905 lastClientRtspMsg = RTSP_SETUP; 00906 00907 string strbuf (buffer); 00908 00909 //change destination-parameter? 00910 if (sp->shouldAddDestination()) 00911 { 00912 uint cpstart; 00913 if ((cpstart = strbuf.find("unicast")) != string::npos) 00914 { 00915 ostringstream strdest; 00916 strdest << "destination=" << inet_ntoa(clientsock->sin_addr) << ";"; 00917 00918 //if there is already an existing destination, replace it, 00919 //otherwise insert it into the string 00920 uint deststart, destend; 00921 if ((deststart = strbuf.find("destination=")) != string::npos) 00922 { 00923 destend = getSmallerStringPos(strbuf, "\r\n", ";"); 00924 strbuf.replace(strbuf.begin()+deststart, strbuf.begin()+destend-1, strdest.str()); 00925 } 00926 else 00927 { 00928 strbuf.insert(cpstart, strdest.str()); 00929 } 00930 } 00931 } 00932 00933 //store track in tracklist 00934 uint tstart = strbuf.find("/trackID="); 00935 if (tstart != string::npos) { 00936 uint tend = strbuf.find(" ", tstart); 00937 uint trackNr = atoi(strbuf.substr(tstart+strlen("/trackID="), tend-(tstart+strlen("/trackID="))).c_str()); 00938 tracks.addTrack(trackNr); 00939 } 00940 00941 forwardToServer((char*)strbuf.c_str(), strbuf.length()); 00942 00943 return true; 00944 00945 }

void SemiProxySession::setUrl const Url uri,
bool  makeExactMatch = true
[virtual]
 

Empty method which is created for conformance to Session.cpp.

Parameters:
uri 
makeExactMatch 

Implements Session.

Definition at line 1173 of file SemiProxySession.cpp.

01174 {}


The documentation for this class was generated from the following files: