#include <SIPClient.hh>
Inheritance diagram for SIPClient:


Public Member Functions | |
| void | setProxyServer (unsigned proxyServerAddress, portNumBits proxyServerPortNum) |
| void | setClientStartPortNum (portNumBits clientStartPortNum) |
| char * | invite (char const *url, Authenticator *authenticator=NULL) |
| char * | inviteWithPassword (char const *url, char const *username, char const *password) |
| Boolean | sendACK () |
| Boolean | sendBYE () |
| char const * | getInviteSdpReply () const |
| UsageEnvironment & | envir () const |
| char const * | name () const |
| virtual Boolean | isSource () const |
| virtual Boolean | isSink () const |
| virtual Boolean | isRTCPInstance () const |
| virtual Boolean | isRTSPClient () const |
| virtual Boolean | isRTSPServer () const |
| virtual Boolean | isMediaSession () const |
| virtual Boolean | isServerMediaSession () const |
| virtual Boolean | isDarwinInjector () const |
Static Public Member Functions | |
| static SIPClient * | createNew (UsageEnvironment &env, unsigned char desiredAudioRTPPayloadFormat, char const *mimeSubtype=NULL, int verbosityLevel=0, char const *applicationName=NULL) |
| static Boolean | parseSIPURL (UsageEnvironment &env, char const *url, NetAddress &address, portNumBits &portNum) |
| static Boolean | parseSIPURLUsernamePassword (char const *url, char *&username, char *&password) |
| static Boolean | lookupByName (UsageEnvironment &env, char const *mediumName, Medium *&resultMedium) |
| static void | close (UsageEnvironment &env, char const *mediumName) |
| static void | close (Medium *medium) |
Protected Member Functions | |
| virtual | ~SIPClient () |
| TaskToken & | nextTask () |
Private Member Functions | |
| SIPClient (UsageEnvironment &env, unsigned char desiredAudioRTPPayloadFormat, char const *mimeSubtype, int verbosityLevel, char const *applicationName) | |
| void | reset () |
| char * | invite1 (Authenticator *authenticator) |
| Boolean | processURL (char const *url) |
| Boolean | sendINVITE () |
| void | doInviteStateMachine (unsigned responseCode) |
| void | doInviteStateTerminated (unsigned responseCode) |
| char * | createAuthenticatorString (Authenticator const *authenticator, char const *cmd, char const *url) |
| Boolean | sendRequest (char const *requestString, unsigned requestLength) |
| unsigned | getResponseCode () |
| unsigned | getResponse (char *&responseBuffer, unsigned responseBufferSize) |
| Boolean | parseResponseCode (char const *line, unsigned &responseCode) |
Static Private Member Functions | |
| static void | inviteResponseHandler (void *clientData, int mask) |
| static void | timerAHandler (void *clientData) |
| static void | timerBHandler (void *clientData) |
| static void | timerDHandler (void *clientData) |
Private Attributes | |
| TaskToken | fTimerA |
| TaskToken | fTimerB |
| TaskToken | fTimerD |
| unsigned const | fT1 |
| unsigned | fTimerALen |
| unsigned | fTimerACount |
| unsigned char | fDesiredAudioRTPPayloadFormat |
| char * | fMIMESubtype |
| unsigned | fMIMESubtypeSize |
| int | fVerbosityLevel |
| unsigned | fCSeq |
| char const * | fApplicationName |
| unsigned | fApplicationNameSize |
| char const * | fOurAddressStr |
| unsigned | fOurAddressStrSize |
| portNumBits | fOurPortNum |
| Groupsock * | fOurSocket |
| char * | fUserAgentHeaderStr |
| unsigned | fUserAgentHeaderStrSize |
| char const * | fURL |
| unsigned | fURLSize |
| in_addr | fServerAddress |
| portNumBits | fServerPortNum |
| portNumBits | fClientStartPortNum |
| unsigned | fCallId |
| unsigned | fFromTag |
| char const * | fToTagStr |
| unsigned | fToTagStrSize |
| Authenticator | fValidAuthenticator |
| char const * | fUserName |
| unsigned | fUserNameSize |
| char * | fInviteSDPDescription |
| char * | fInviteSDPDescriptionReturned |
| char * | fInviteCmd |
| unsigned | fInviteCmdSize |
| Authenticator * | fWorkingAuthenticator |
| inviteClientState | fInviteClientState |
| char | fEventLoopStopFlag |
Friends | |
| class | MediaLookupTable |
Definition at line 37 of file SIPClient.hh.
| SIPClient::~SIPClient | ( | ) | [protected, virtual] |
Definition at line 120 of file SIPClient.cpp.
References fApplicationName, fMIMESubtype, fOurAddressStr, fOurSocket, fUserAgentHeaderStr, and reset().
00120 { 00121 reset(); 00122 00123 delete[] fUserAgentHeaderStr; 00124 delete fOurSocket; 00125 delete[] (char*)fOurAddressStr; 00126 delete[] (char*)fApplicationName; 00127 delete[] (char*)fMIMESubtype; 00128 }
| SIPClient::SIPClient | ( | UsageEnvironment & | env, | |
| unsigned char | desiredAudioRTPPayloadFormat, | |||
| char const * | mimeSubtype, | |||
| int | verbosityLevel, | |||
| char const * | applicationName | |||
| ) | [private] |
Definition at line 41 of file SIPClient.cpp.
References env, Medium::envir(), fApplicationName, fApplicationNameSize, fMIMESubtype, fMIMESubtypeSize, fOurAddressStr, fOurAddressStrSize, fOurPortNum, fOurSocket, fUserAgentHeaderStr, fUserAgentHeaderStrSize, UsageEnvironment::getResultMsg(), getSourcePort(), libVersionStr, LIVEMEDIA_LIBRARY_VERSION_STRING, NULL, Port::num(), ourIPAddress(), Groupsock::output(), reset(), Socket::socketNum(), and strDup().
00045 : Medium(env), 00046 fT1(500000 /* 500 ms */), 00047 fDesiredAudioRTPPayloadFormat(desiredAudioRTPPayloadFormat), 00048 fVerbosityLevel(verbosityLevel), 00049 fCSeq(0), fURL(NULL), fURLSize(0), 00050 fToTagStr(NULL), fToTagStrSize(0), 00051 fUserName(NULL), fUserNameSize(0), 00052 fInviteSDPDescription(NULL), fInviteSDPDescriptionReturned(NULL), 00053 fInviteCmd(NULL), fInviteCmdSize(0) { 00054 if (mimeSubtype == NULL) mimeSubtype = ""; 00055 fMIMESubtype = strDup(mimeSubtype); 00056 fMIMESubtypeSize = strlen(fMIMESubtype); 00057 00058 if (applicationName == NULL) applicationName = ""; 00059 fApplicationName = strDup(applicationName); 00060 fApplicationNameSize = strlen(fApplicationName); 00061 00062 struct in_addr ourAddress; 00063 ourAddress.s_addr = ourIPAddress(env); // hack 00064 fOurAddressStr = strDup(AddressString(ourAddress).val()); 00065 fOurAddressStrSize = strlen(fOurAddressStr); 00066 00067 fOurSocket = new Groupsock(env, ourAddress, 0, 255); 00068 if (fOurSocket == NULL) { 00069 env << "ERROR: Failed to create socket for addr " 00070 << fOurAddressStr << ": " 00071 << env.getResultMsg() << "\n"; 00072 } 00073 00074 // Now, find out our source port number. Hack: Do this by first trying to 00075 // send a 0-length packet, so that the "getSourcePort()" call will work. 00076 fOurSocket->output(envir(), 255, (unsigned char*)"", 0); 00077 Port srcPort(0); 00078 getSourcePort(env, fOurSocket->socketNum(), srcPort); 00079 if (srcPort.num() != 0) { 00080 fOurPortNum = ntohs(srcPort.num()); 00081 } else { 00082 // No luck. Try again using a default port number: 00083 fOurPortNum = 5060; 00084 delete fOurSocket; 00085 fOurSocket = new Groupsock(env, ourAddress, fOurPortNum, 255); 00086 if (fOurSocket == NULL) { 00087 env << "ERROR: Failed to create socket for addr " 00088 << fOurAddressStr << ", port " 00089 << fOurPortNum << ": " 00090 << env.getResultMsg() << "\n"; 00091 } 00092 } 00093 00094 // Set various headers to be used in each request: 00095 char const* formatStr; 00096 unsigned headerSize; 00097 00098 // Set the "User-Agent:" header: 00099 char const* const libName = "LIVE555 Streaming Media v"; 00100 char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; 00101 char const* libPrefix; char const* libSuffix; 00102 if (applicationName == NULL || applicationName[0] == '\0') { 00103 applicationName = libPrefix = libSuffix = ""; 00104 } else { 00105 libPrefix = " ("; 00106 libSuffix = ")"; 00107 } 00108 formatStr = "User-Agent: %s%s%s%s%s\r\n"; 00109 headerSize 00110 = strlen(formatStr) + fApplicationNameSize + strlen(libPrefix) 00111 + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix); 00112 fUserAgentHeaderStr = new char[headerSize]; 00113 sprintf(fUserAgentHeaderStr, formatStr, 00114 applicationName, libPrefix, libName, libVersionStr, libSuffix); 00115 fUserAgentHeaderStrSize = strlen(fUserAgentHeaderStr); 00116 00117 reset(); 00118 }
| SIPClient * SIPClient::createNew | ( | UsageEnvironment & | env, | |
| unsigned char | desiredAudioRTPPayloadFormat, | |||
| char const * | mimeSubtype = NULL, |
|||
| int | verbosityLevel = 0, |
|||
| char const * | applicationName = NULL | |||
| ) | [static] |
Definition at line 33 of file SIPClient.cpp.
References env.
Referenced by createClient().
00036 { 00037 return new SIPClient(env, desiredAudioRTPPayloadFormat, mimeSubtype, 00038 verbosityLevel, applicationName); 00039 }
| void SIPClient::setProxyServer | ( | unsigned | proxyServerAddress, | |
| portNumBits | proxyServerPortNum | |||
| ) |
Definition at line 146 of file SIPClient.cpp.
References Groupsock::changeDestinationParameters(), fOurSocket, fServerAddress, fServerPortNum, and NULL.
Referenced by getSDPDescription().
00147 { 00148 fServerAddress.s_addr = proxyServerAddress; 00149 fServerPortNum = proxyServerPortNum; 00150 if (fOurSocket != NULL) { 00151 fOurSocket->changeDestinationParameters(fServerAddress, 00152 fServerPortNum, 255); 00153 } 00154 }
| void SIPClient::setClientStartPortNum | ( | portNumBits | clientStartPortNum | ) | [inline] |
Definition at line 48 of file SIPClient.hh.
References fClientStartPortNum.
Referenced by getSDPDescription().
00048 { 00049 fClientStartPortNum = clientStartPortNum; 00050 }
| char * SIPClient::invite | ( | char const * | url, | |
| Authenticator * | authenticator = NULL | |||
| ) |
Definition at line 170 of file SIPClient.cpp.
References fCallId, fFromTag, fURL, fURLSize, invite1(), inviteWithPassword(), NULL, our_random32(), parseSIPURLUsernamePassword(), password, processURL(), strDup(), and username.
Referenced by getSDPDescription(), and inviteWithPassword().
00170 { 00171 // First, check whether "url" contains a username:password to be used: 00172 char* username; char* password; 00173 if (authenticator == NULL 00174 && parseSIPURLUsernamePassword(url, username, password)) { 00175 char* result = inviteWithPassword(url, username, password); 00176 delete[] username; delete[] password; // they were dynamically allocated 00177 return result; 00178 } 00179 00180 if (!processURL(url)) return NULL; 00181 00182 delete[] (char*)fURL; fURL = strDup(url); 00183 fURLSize = strlen(fURL); 00184 00185 fCallId = our_random32(); 00186 fFromTag = our_random32(); 00187 00188 return invite1(authenticator); 00189 }
| char * SIPClient::inviteWithPassword | ( | char const * | url, | |
| char const * | username, | |||
| char const * | password | |||
| ) |
Definition at line 608 of file SIPClient.cpp.
References fUserName, fUserNameSize, fValidAuthenticator, invite(), invite1(), Authenticator::nonce(), NULL, Authenticator::realm(), and strDup().
Referenced by getSDPDescription(), and invite().
00609 { 00610 delete[] (char*)fUserName; fUserName = strDup(username); 00611 fUserNameSize = strlen(fUserName); 00612 00613 Authenticator authenticator(username, password); 00614 char* inviteResult = invite(url, &authenticator); 00615 if (inviteResult != NULL) { 00616 // We are already authorized 00617 return inviteResult; 00618 } 00619 00620 // The "realm" and "nonce" fields should have been filled in: 00621 if (authenticator.realm() == NULL || authenticator.nonce() == NULL) { 00622 // We haven't been given enough information to try again, so fail: 00623 return NULL; 00624 } 00625 00626 // Try again (but with the same CallId): 00627 inviteResult = invite1(&authenticator); 00628 if (inviteResult != NULL) { 00629 // The authenticator worked, so use it in future requests: 00630 fValidAuthenticator = authenticator; 00631 } 00632 00633 return inviteResult; 00634 }
| Boolean SIPClient::sendACK | ( | ) |
Definition at line 636 of file SIPClient.cpp.
References Medium::envir(), False, fCallId, fCSeq, fFromTag, fOurAddressStr, fOurAddressStrSize, fOurPortNum, fToTagStr, fToTagStrSize, fURL, fURLSize, fUserName, fUserNameSize, NULL, sendRequest(), UsageEnvironment::setResultErrMsg(), and True.
Referenced by doInviteStateMachine(), and startPlayingSession().
00636 { 00637 char* cmd = NULL; 00638 do { 00639 char const* const cmdFmt = 00640 "ACK %s SIP/2.0\r\n" 00641 "From: %s <sip:%s@%s>;tag=%u\r\n" 00642 "Via: SIP/2.0/UDP %s:%u\r\n" 00643 "Max-Forwards: 70\r\n" 00644 "To: %s;tag=%s\r\n" 00645 "Call-ID: %u@%s\r\n" 00646 "CSeq: %d ACK\r\n" 00647 "Content-Length: 0\r\n\r\n"; 00648 unsigned cmdSize = strlen(cmdFmt) 00649 + fURLSize 00650 + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */ 00651 + fOurAddressStrSize + 5 /* max port len */ 00652 + fURLSize + fToTagStrSize 00653 + 20 + fOurAddressStrSize 00654 + 20; 00655 cmd = new char[cmdSize]; 00656 sprintf(cmd, cmdFmt, 00657 fURL, 00658 fUserName, fUserName, fOurAddressStr, fFromTag, 00659 fOurAddressStr, fOurPortNum, 00660 fURL, fToTagStr, 00661 fCallId, fOurAddressStr, 00662 fCSeq /* note: it's the same as before; not incremented */); 00663 00664 if (!sendRequest(cmd, strlen(cmd))) { 00665 envir().setResultErrMsg("ACK send() failed: "); 00666 break; 00667 } 00668 00669 delete[] cmd; 00670 return True; 00671 } while (0); 00672 00673 delete[] cmd; 00674 return False; 00675 }
| Boolean SIPClient::sendBYE | ( | ) |
Definition at line 677 of file SIPClient.cpp.
References Medium::envir(), False, fCallId, fCSeq, fFromTag, fOurAddressStr, fOurAddressStrSize, fOurPortNum, fToTagStr, fToTagStrSize, fURL, fURLSize, fUserName, fUserNameSize, NULL, sendRequest(), UsageEnvironment::setResultErrMsg(), and True.
Referenced by tearDownSession().
00677 { 00678 // NOTE: This should really be retransmitted, for reliability ##### 00679 char* cmd = NULL; 00680 do { 00681 char const* const cmdFmt = 00682 "BYE %s SIP/2.0\r\n" 00683 "From: %s <sip:%s@%s>;tag=%u\r\n" 00684 "Via: SIP/2.0/UDP %s:%u\r\n" 00685 "Max-Forwards: 70\r\n" 00686 "To: %s;tag=%s\r\n" 00687 "Call-ID: %u@%s\r\n" 00688 "CSeq: %d BYE\r\n" 00689 "Content-Length: 0\r\n\r\n"; 00690 unsigned cmdSize = strlen(cmdFmt) 00691 + fURLSize 00692 + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */ 00693 + fOurAddressStrSize + 5 /* max port len */ 00694 + fURLSize + fToTagStrSize 00695 + 20 + fOurAddressStrSize 00696 + 20; 00697 cmd = new char[cmdSize]; 00698 sprintf(cmd, cmdFmt, 00699 fURL, 00700 fUserName, fUserName, fOurAddressStr, fFromTag, 00701 fOurAddressStr, fOurPortNum, 00702 fURL, fToTagStr, 00703 fCallId, fOurAddressStr, 00704 ++fCSeq); 00705 00706 if (!sendRequest(cmd, strlen(cmd))) { 00707 envir().setResultErrMsg("BYE send() failed: "); 00708 break; 00709 } 00710 00711 delete[] cmd; 00712 return True; 00713 } while (0); 00714 00715 delete[] cmd; 00716 return False; 00717 }
| Boolean SIPClient::parseSIPURL | ( | UsageEnvironment & | env, | |
| char const * | url, | |||
| NetAddress & | address, | |||
| portNumBits & | portNum | |||
| ) | [static] |
Definition at line 740 of file SIPClient.cpp.
References _strncasecmp, env, False, NetAddressList::firstAddress(), NetAddressList::numAddresses(), UsageEnvironment::setResultMsg(), and True.
Referenced by processURL().
00742 { 00743 do { 00744 // Parse the URL as "sip:<username>@<address>:<port>/<etc>" 00745 // (with ":<port>" and "/<etc>" optional) 00746 // Also, skip over any "<username>[:<password>]@" preceding <address> 00747 char const* prefix = "sip:"; 00748 unsigned const prefixLength = 4; 00749 if (_strncasecmp(url, prefix, prefixLength) != 0) { 00750 env.setResultMsg("URL is not of the form \"", prefix, "\""); 00751 break; 00752 } 00753 00754 unsigned const parseBufferSize = 100; 00755 char parseBuffer[parseBufferSize]; 00756 unsigned addressStartIndex = prefixLength; 00757 while (url[addressStartIndex] != '\0' 00758 && url[addressStartIndex++] != '@') {} 00759 char const* from = &url[addressStartIndex]; 00760 00761 // Skip over any "<username>[:<password>]@" 00762 char const* from1 = from; 00763 while (*from1 != '\0' && *from1 != '/') { 00764 if (*from1 == '@') { 00765 from = ++from1; 00766 break; 00767 } 00768 ++from1; 00769 } 00770 00771 char* to = &parseBuffer[0]; 00772 unsigned i; 00773 for (i = 0; i < parseBufferSize; ++i) { 00774 if (*from == '\0' || *from == ':' || *from == '/') { 00775 // We've completed parsing the address 00776 *to = '\0'; 00777 break; 00778 } 00779 *to++ = *from++; 00780 } 00781 if (i == parseBufferSize) { 00782 env.setResultMsg("URL is too long"); 00783 break; 00784 } 00785 00786 NetAddressList addresses(parseBuffer); 00787 if (addresses.numAddresses() == 0) { 00788 env.setResultMsg("Failed to find network address for \"", 00789 parseBuffer, "\""); 00790 break; 00791 } 00792 address = *(addresses.firstAddress()); 00793 00794 portNum = 5060; // default value 00795 char nextChar = *from; 00796 if (nextChar == ':') { 00797 int portNumInt; 00798 if (sscanf(++from, "%d", &portNumInt) != 1) { 00799 env.setResultMsg("No port number follows ':'"); 00800 break; 00801 } 00802 if (portNumInt < 1 || portNumInt > 65535) { 00803 env.setResultMsg("Bad port number"); 00804 break; 00805 } 00806 portNum = (portNumBits)portNumInt; 00807 } 00808 00809 return True; 00810 } while (0); 00811 00812 return False; 00813 }
| Boolean SIPClient::parseSIPURLUsernamePassword | ( | char const * | url, | |
| char *& | username, | |||
| char *& | password | |||
| ) | [static] |
Definition at line 815 of file SIPClient.cpp.
References _strncasecmp, False, NULL, strDup(), and True.
Referenced by invite().
00817 { 00818 username = password = NULL; // by default 00819 do { 00820 // Parse the URL as "sip:<username>[:<password>]@<whatever>" 00821 char const* prefix = "sip:"; 00822 unsigned const prefixLength = 4; 00823 if (_strncasecmp(url, prefix, prefixLength) != 0) break; 00824 00825 // Look for the ':' and '@': 00826 unsigned usernameIndex = prefixLength; 00827 unsigned colonIndex = 0, atIndex = 0; 00828 for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) { 00829 if (url[i] == ':' && colonIndex == 0) { 00830 colonIndex = i; 00831 } else if (url[i] == '@') { 00832 atIndex = i; 00833 break; // we're done 00834 } 00835 } 00836 if (atIndex == 0) break; // no '@' found 00837 00838 char* urlCopy = strDup(url); 00839 urlCopy[atIndex] = '\0'; 00840 if (colonIndex > 0) { 00841 urlCopy[colonIndex] = '\0'; 00842 password = strDup(&urlCopy[colonIndex+1]); 00843 } else { 00844 password = strDup(""); 00845 } 00846 username = strDup(&urlCopy[usernameIndex]); 00847 delete[] urlCopy; 00848 00849 return True; 00850 } while (0); 00851 00852 return False; 00853 }
| char const* SIPClient::getInviteSdpReply | ( | ) | const [inline] |
Definition at line 70 of file SIPClient.hh.
References fInviteSDPDescriptionReturned.
Referenced by setupSubsession().
00070 { return fInviteSDPDescriptionReturned; }
| void SIPClient::reset | ( | ) | [private] |
Definition at line 130 of file SIPClient.cpp.
References fApplicationName, fInviteCmd, fInviteCmdSize, fInviteSDPDescription, fServerAddress, fServerPortNum, fToTagStr, fToTagStrSize, fURL, fURLSize, fUserName, fUserNameSize, fValidAuthenticator, fWorkingAuthenticator, NULL, Authenticator::reset(), and strDup().
Referenced by SIPClient(), and ~SIPClient().
00130 { 00131 fWorkingAuthenticator = NULL; 00132 delete[] fInviteCmd; fInviteCmd = NULL; fInviteCmdSize = 0; 00133 delete[] fInviteSDPDescription; fInviteSDPDescription = NULL; 00134 00135 delete[] (char*)fUserName; fUserName = strDup(fApplicationName); 00136 fUserNameSize = strlen(fUserName); 00137 00138 fValidAuthenticator.reset(); 00139 00140 delete[] (char*)fToTagStr; fToTagStr = NULL; fToTagStrSize = 0; 00141 fServerPortNum = 0; 00142 fServerAddress.s_addr = 0; 00143 delete[] (char*)fURL; fURL = NULL; fURLSize = 0; 00144 }
| char * SIPClient::invite1 | ( | Authenticator * | authenticator | ) | [private] |
Definition at line 191 of file SIPClient.cpp.
References Calling, createAuthenticatorString(), TaskScheduler::doEventLoop(), Medium::envir(), fApplicationName, fApplicationNameSize, fCallId, fClientStartPortNum, fCSeq, fDesiredAudioRTPPayloadFormat, fEventLoopStopFlag, fFromTag, fInviteClientState, fInviteCmd, fInviteCmdSize, fInviteSDPDescription, fMIMESubtype, fMIMESubtypeSize, fOurAddressStr, fOurAddressStrSize, fOurPortNum, fOurSocket, fT1, fTimerA, fTimerACount, fTimerALen, fTimerB, fTimerD, fURL, fURLSize, fUserAgentHeaderStr, fUserAgentHeaderStrSize, fUserName, fUserNameSize, fValidAuthenticator, fWorkingAuthenticator, inviteResponseHandler(), NULL, Authenticator::reset(), TaskScheduler::scheduleDelayedTask(), sendINVITE(), Socket::socketNum(), strDup(), UsageEnvironment::taskScheduler(), timerAHandler(), timerBHandler(), TaskScheduler::turnOffBackgroundReadHandling(), TaskScheduler::turnOnBackgroundReadHandling(), and TaskScheduler::unscheduleDelayedTask().
Referenced by invite(), and inviteWithPassword().
00191 { 00192 do { 00193 // Send the INVITE command: 00194 00195 // First, construct an authenticator string: 00196 fValidAuthenticator.reset(); 00197 fWorkingAuthenticator = authenticator; 00198 char* authenticatorStr 00199 = createAuthenticatorString(fWorkingAuthenticator, "INVITE", fURL); 00200 00201 // Then, construct the SDP description to be sent in the INVITE: 00202 char* rtpmapLine; 00203 unsigned rtpmapLineSize; 00204 if (fMIMESubtypeSize > 0) { 00205 char const* const rtpmapFmt = 00206 "a=rtpmap:%u %s/8000\r\n"; 00207 unsigned rtpmapFmtSize = strlen(rtpmapFmt) 00208 + 3 /* max char len */ + fMIMESubtypeSize; 00209 rtpmapLine = new char[rtpmapFmtSize]; 00210 sprintf(rtpmapLine, rtpmapFmt, 00211 fDesiredAudioRTPPayloadFormat, fMIMESubtype); 00212 rtpmapLineSize = strlen(rtpmapLine); 00213 } else { 00214 // Static payload type => no "a=rtpmap:" line 00215 rtpmapLine = strDup(""); 00216 rtpmapLineSize = 0; 00217 } 00218 char const* const inviteSDPFmt = 00219 "v=0\r\n" 00220 "o=- %u %u IN IP4 %s\r\n" 00221 "s=%s session\r\n" 00222 "c=IN IP4 %s\r\n" 00223 "t=0 0\r\n" 00224 "m=audio %u RTP/AVP %u\r\n" 00225 "%s"; 00226 unsigned inviteSDPFmtSize = strlen(inviteSDPFmt) 00227 + 20 /* max int len */ + 20 + fOurAddressStrSize 00228 + fApplicationNameSize 00229 + fOurAddressStrSize 00230 + 5 /* max short len */ + 3 /* max char len */ 00231 + rtpmapLineSize; 00232 delete[] fInviteSDPDescription; 00233 fInviteSDPDescription = new char[inviteSDPFmtSize]; 00234 sprintf(fInviteSDPDescription, inviteSDPFmt, 00235 fCallId, fCSeq, fOurAddressStr, 00236 fApplicationName, 00237 fOurAddressStr, 00238 fClientStartPortNum, fDesiredAudioRTPPayloadFormat, 00239 rtpmapLine); 00240 unsigned inviteSDPSize = strlen(fInviteSDPDescription); 00241 delete[] rtpmapLine; 00242 00243 char const* const cmdFmt = 00244 "INVITE %s SIP/2.0\r\n" 00245 "From: %s <sip:%s@%s>;tag=%u\r\n" 00246 "Via: SIP/2.0/UDP %s:%u\r\n" 00247 "Max-Forwards: 70\r\n" 00248 "To: %s\r\n" 00249 "Contact: sip:%s@%s:%u\r\n" 00250 "Call-ID: %u@%s\r\n" 00251 "CSeq: %d INVITE\r\n" 00252 "Content-Type: application/sdp\r\n" 00253 "%s" /* Proxy-Authorization: line (if any) */ 00254 "%s" /* User-Agent: line */ 00255 "Content-Length: %d\r\n\r\n" 00256 "%s"; 00257 unsigned inviteCmdSize = strlen(cmdFmt) 00258 + fURLSize 00259 + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */ 00260 + fOurAddressStrSize + 5 /* max port len */ 00261 + fURLSize 00262 + fUserNameSize + fOurAddressStrSize + 5 00263 + 20 + fOurAddressStrSize 00264 + 20 00265 + strlen(authenticatorStr) 00266 + fUserAgentHeaderStrSize 00267 + 20 00268 + inviteSDPSize; 00269 delete[] fInviteCmd; fInviteCmd = new char[inviteCmdSize]; 00270 sprintf(fInviteCmd, cmdFmt, 00271 fURL, 00272 fUserName, fUserName, fOurAddressStr, fFromTag, 00273 fOurAddressStr, fOurPortNum, 00274 fURL, 00275 fUserName, fOurAddressStr, fOurPortNum, 00276 fCallId, fOurAddressStr, 00277 ++fCSeq, 00278 authenticatorStr, 00279 fUserAgentHeaderStr, 00280 inviteSDPSize, 00281 fInviteSDPDescription); 00282 fInviteCmdSize = strlen(fInviteCmd); 00283 delete[] authenticatorStr; 00284 00285 // Before sending the "INVITE", arrange to handle any response packets, 00286 // and set up timers: 00287 fInviteClientState = Calling; 00288 fEventLoopStopFlag = 0; 00289 TaskScheduler& sched = envir().taskScheduler(); // abbrev. 00290 sched.turnOnBackgroundReadHandling(fOurSocket->socketNum(), 00291 &inviteResponseHandler, this); 00292 fTimerALen = 1*fT1; // initially 00293 fTimerACount = 0; // initially 00294 fTimerA = sched.scheduleDelayedTask(fTimerALen, timerAHandler, this); 00295 fTimerB = sched.scheduleDelayedTask(64*fT1, timerBHandler, this); 00296 fTimerD = NULL; // for now 00297 00298 if (!sendINVITE()) break; 00299 00300 // Enter the event loop, to handle response packets, and timeouts: 00301 envir().taskScheduler().doEventLoop(&fEventLoopStopFlag); 00302 00303 // We're finished with this "INVITE". 00304 // Turn off response handling and timers: 00305 sched.turnOffBackgroundReadHandling(fOurSocket->socketNum()); 00306 sched.unscheduleDelayedTask(fTimerA); 00307 sched.unscheduleDelayedTask(fTimerB); 00308 sched.unscheduleDelayedTask(fTimerD); 00309 00310 // NOTE: We return the SDP description that we used in the "INVITE", 00311 // not the one that we got from the server. 00312 // ##### Later: match the codecs in the response (offer, answer) ##### 00313 if (fInviteSDPDescription != NULL) { 00314 return strDup(fInviteSDPDescription); 00315 } 00316 } while (0); 00317 00318 return NULL; 00319 }
| Boolean SIPClient::processURL | ( | char const * | url | ) | [private] |
Definition at line 719 of file SIPClient.cpp.
References Groupsock::changeDestinationParameters(), NetAddress::data(), Medium::envir(), False, fOurSocket, fServerAddress, fServerPortNum, NULL, parseSIPURL(), and True.
Referenced by invite().
00719 { 00720 do { 00721 // If we don't already have a server address/port, then 00722 // get these by parsing the URL: 00723 if (fServerAddress.s_addr == 0) { 00724 NetAddress destAddress; 00725 if (!parseSIPURL(envir(), url, destAddress, fServerPortNum)) break; 00726 fServerAddress.s_addr = *(unsigned*)(destAddress.data()); 00727 00728 if (fOurSocket != NULL) { 00729 fOurSocket->changeDestinationParameters(fServerAddress, 00730 fServerPortNum, 255); 00731 } 00732 } 00733 00734 return True; 00735 } while (0); 00736 00737 return False; 00738 }
| Boolean SIPClient::sendINVITE | ( | ) | [private] |
Definition at line 444 of file SIPClient.cpp.
References Medium::envir(), False, fInviteCmd, fInviteCmdSize, sendRequest(), UsageEnvironment::setResultErrMsg(), and True.
Referenced by doInviteStateMachine(), and invite1().
00444 { 00445 if (!sendRequest(fInviteCmd, fInviteCmdSize)) { 00446 envir().setResultErrMsg("INVITE send() failed: "); 00447 return False; 00448 } 00449 return True; 00450 }
| void SIPClient::inviteResponseHandler | ( | void * | clientData, | |
| int | mask | |||
| ) | [static, private] |
Definition at line 321 of file SIPClient.cpp.
References doInviteStateMachine(), and getResponseCode().
Referenced by invite1().
00321 { 00322 SIPClient* client = (SIPClient*)clientData; 00323 unsigned responseCode = client->getResponseCode(); 00324 client->doInviteStateMachine(responseCode); 00325 }
| void SIPClient::doInviteStateMachine | ( | unsigned | responseCode | ) | [private] |
Definition at line 360 of file SIPClient.cpp.
References Calling, Completed, doInviteStateTerminated(), Medium::envir(), fInviteClientState, fTimerA, fTimerALen, fTimerB, fTimerD, Proceeding, TaskScheduler::scheduleDelayedTask(), sendACK(), sendINVITE(), UsageEnvironment::setResultMsg(), UsageEnvironment::taskScheduler(), Terminated, timerAFires, timerAHandler(), timerBFires, timerDFires, timerDHandler(), and TaskScheduler::unscheduleDelayedTask().
Referenced by inviteResponseHandler(), timerAHandler(), timerBHandler(), and timerDHandler().
00360 { 00361 // Implement the state transition diagram (RFC 3261, Figure 5) 00362 TaskScheduler& sched = envir().taskScheduler(); // abbrev. 00363 switch (fInviteClientState) { 00364 case Calling: { 00365 if (responseCode == timerAFires) { 00366 // Restart timer A (with double the timeout interval): 00367 fTimerALen *= 2; 00368 fTimerA 00369 = sched.scheduleDelayedTask(fTimerALen, timerAHandler, this); 00370 00371 fInviteClientState = Calling; 00372 if (!sendINVITE()) doInviteStateTerminated(0); 00373 } else { 00374 // Turn off timers A & B before moving to a new state: 00375 sched.unscheduleDelayedTask(fTimerA); 00376 sched.unscheduleDelayedTask(fTimerB); 00377 00378 if (responseCode == timerBFires) { 00379 envir().setResultMsg("No response from server"); 00380 doInviteStateTerminated(0); 00381 } else if (responseCode >= 100 && responseCode <= 199) { 00382 fInviteClientState = Proceeding; 00383 } else if (responseCode >= 200 && responseCode <= 299) { 00384 doInviteStateTerminated(responseCode); 00385 } else if (responseCode >= 400 && responseCode <= 499) { 00386 doInviteStateTerminated(responseCode); 00387 // this isn't what the spec says, but it seems right... 00388 } else if (responseCode >= 300 && responseCode <= 699) { 00389 fInviteClientState = Completed; 00390 fTimerD 00391 = sched.scheduleDelayedTask(32000000, timerDHandler, this); 00392 if (!sendACK()) doInviteStateTerminated(0); 00393 } 00394 } 00395 break; 00396 } 00397 00398 case Proceeding: { 00399 if (responseCode >= 100 && responseCode <= 199) { 00400 fInviteClientState = Proceeding; 00401 } else if (responseCode >= 200 && responseCode <= 299) { 00402 doInviteStateTerminated(responseCode); 00403 } else if (responseCode >= 400 && responseCode <= 499) { 00404 doInviteStateTerminated(responseCode); 00405 // this isn't what the spec says, but it seems right... 00406 } else if (responseCode >= 300 && responseCode <= 699) { 00407 fInviteClientState = Completed; 00408 fTimerD = sched.scheduleDelayedTask(32000000, timerDHandler, this); 00409 if (!sendACK()) doInviteStateTerminated(0); 00410 } 00411 break; 00412 } 00413 00414 case Completed: { 00415 if (responseCode == timerDFires) { 00416 envir().setResultMsg("Transaction terminated"); 00417 doInviteStateTerminated(0); 00418 } else if (responseCode >= 300 && responseCode <= 699) { 00419 fInviteClientState = Completed; 00420 if (!sendACK()) doInviteStateTerminated(0); 00421 } 00422 break; 00423 } 00424 00425 case Terminated: { 00426 doInviteStateTerminated(responseCode); 00427 break; 00428 } 00429 } 00430 }
| void SIPClient::doInviteStateTerminated | ( | unsigned | responseCode | ) | [private] |
Definition at line 432 of file SIPClient.cpp.
References fEventLoopStopFlag, fInviteClientState, fInviteSDPDescription, fInviteSDPDescriptionReturned, NULL, and Terminated.
Referenced by doInviteStateMachine().
00432 { 00433 fInviteClientState = Terminated; // FWIW... 00434 if (responseCode < 200 || responseCode > 299) { 00435 // We failed, so return NULL; 00436 delete[] fInviteSDPDescription; fInviteSDPDescription = NULL; 00437 delete[] fInviteSDPDescriptionReturned; fInviteSDPDescriptionReturned = NULL; 00438 } 00439 00440 // Unblock the event loop: 00441 fEventLoopStopFlag = ~0; 00442 }
| void SIPClient::timerAHandler | ( | void * | clientData | ) | [static, private] |
Definition at line 332 of file SIPClient.cpp.
References doInviteStateMachine(), Medium::envir(), fTimerACount, fTimerALen, fVerbosityLevel, and timerAFires.
Referenced by doInviteStateMachine(), and invite1().
00332 { 00333 SIPClient* client = (SIPClient*)clientData; 00334 if (client->fVerbosityLevel >= 1) { 00335 client->envir() << "RETRANSMISSION " << ++client->fTimerACount 00336 << ", after " << client->fTimerALen/1000000.0 00337 << " additional seconds\n"; 00338 } 00339 client->doInviteStateMachine(timerAFires); 00340 }
| void SIPClient::timerBHandler | ( | void * | clientData | ) | [static, private] |
Definition at line 342 of file SIPClient.cpp.
References doInviteStateMachine(), Medium::envir(), fT1, fVerbosityLevel, and timerBFires.
Referenced by invite1().
00342 { 00343 SIPClient* client = (SIPClient*)clientData; 00344 if (client->fVerbosityLevel >= 1) { 00345 client->envir() << "RETRANSMISSION TIMEOUT, after " 00346 << 64*client->fT1/1000000.0 << " seconds\n"; 00347 fflush(stderr); 00348 } 00349 client->doInviteStateMachine(timerBFires); 00350 }
| void SIPClient::timerDHandler | ( | void * | clientData | ) | [static, private] |
Definition at line 352 of file SIPClient.cpp.
References doInviteStateMachine(), Medium::envir(), fVerbosityLevel, and timerDFires.
Referenced by doInviteStateMachine().
00352 { 00353 SIPClient* client = (SIPClient*)clientData; 00354 if (client->fVerbosityLevel >= 1) { 00355 client->envir() << "TIMER D EXPIRED\n"; 00356 } 00357 client->doInviteStateMachine(timerDFires); 00358 }
| char * SIPClient::createAuthenticatorString | ( | Authenticator const * | authenticator, | |
| char const * | cmd, | |||
| char const * | url | |||
| ) | [private] |
Definition at line 856 of file SIPClient.cpp.
References Authenticator::computeDigestResponse(), Authenticator::nonce(), NULL, Authenticator::password(), Authenticator::realm(), Authenticator::reclaimDigestResponse(), strDup(), and Authenticator::username().
Referenced by invite1().
00857 { 00858 if (authenticator != NULL && authenticator->realm() != NULL 00859 && authenticator->nonce() != NULL && authenticator->username() != NULL 00860 && authenticator->password() != NULL) { 00861 // We've been provided a filled-in authenticator, so use it: 00862 char const* const authFmt 00863 = "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", response=\"%s\", uri=\"%s\"\r\n"; 00864 char const* response = authenticator->computeDigestResponse(cmd, url); 00865 unsigned authBufSize = strlen(authFmt) 00866 + strlen(authenticator->username()) + strlen(authenticator->realm()) 00867 + strlen(authenticator->nonce()) + strlen(url) + strlen(response); 00868 char* authenticatorStr = new char[authBufSize]; 00869 sprintf(authenticatorStr, authFmt, 00870 authenticator->username(), authenticator->realm(), 00871 authenticator->nonce(), response, url); 00872 authenticator->reclaimDigestResponse(response); 00873 00874 return authenticatorStr; 00875 } 00876 00877 return strDup(""); 00878 }
| Boolean SIPClient::sendRequest | ( | char const * | requestString, | |
| unsigned | requestLength | |||
| ) | [private] |
Definition at line 880 of file SIPClient.cpp.
References Medium::envir(), fOurSocket, fVerbosityLevel, and Groupsock::output().
Referenced by sendACK(), sendBYE(), and sendINVITE().
00881 { 00882 if (fVerbosityLevel >= 1) { 00883 envir() << "Sending request: " << requestString << "\n"; 00884 } 00885 // NOTE: We should really check that "requestLength" is not ##### 00886 // too large for UDP (see RFC 3261, section 18.1.1) ##### 00887 return fOurSocket->output(envir(), 255, (unsigned char*)requestString, 00888 requestLength); 00889 }
| unsigned SIPClient::getResponseCode | ( | ) | [private] |
Definition at line 452 of file SIPClient.cpp.
References Medium::envir(), False, fInviteSDPDescriptionReturned, fOurSocket, fToTagStr, fToTagStrSize, fVerbosityLevel, fWorkingAuthenticator, getLine(), getResponse(), Groupsock::handleRead(), NULL, parseResponseCode(), Authenticator::setRealmAndNonce(), UsageEnvironment::setResultMsg(), strDup(), strDupSize(), and True.
Referenced by inviteResponseHandler().
00452 { 00453 unsigned responseCode = 0; 00454 do { 00455 // Get the response from the server: 00456 unsigned const readBufSize = 10000; 00457 char readBuffer[readBufSize+1]; char* readBuf = readBuffer; 00458 00459 char* firstLine = NULL; 00460 char* nextLineStart = NULL; 00461 unsigned bytesRead = getResponse(readBuf, readBufSize); 00462 if (bytesRead == 0) break; 00463 if (fVerbosityLevel >= 1) { 00464 envir() << "Received INVITE response: " << readBuf << "\n"; 00465 } 00466 00467 // Inspect the first line to get the response code: 00468 firstLine = readBuf; 00469 nextLineStart = getLine(firstLine); 00470 if (!parseResponseCode(firstLine, responseCode)) break; 00471 00472 if (responseCode != 200) { 00473 if (responseCode >= 400 && responseCode <= 499 00474 && fWorkingAuthenticator != NULL) { 00475 // We have an authentication failure, so fill in 00476 // "*fWorkingAuthenticator" using the contents of a following 00477 // "Proxy-Authenticate:" line. (Once we compute a 'response' for 00478 // "fWorkingAuthenticator", it can be used in a subsequent request 00479 // - that will hopefully succeed.) 00480 char* lineStart; 00481 while (1) { 00482 lineStart = nextLineStart; 00483 if (lineStart == NULL) break; 00484 00485 nextLineStart = getLine(lineStart); 00486 if (lineStart[0] == '\0') break; // this is a blank line 00487 00488 char* realm = strDupSize(lineStart); 00489 char* nonce = strDupSize(lineStart); 00490 // ##### Check for the format of "Proxy-Authenticate:" lines from 00491 // ##### known server types. 00492 // ##### This is a crock! We should make the parsing more general 00493 Boolean foundAuthenticateHeader = False; 00494 if ( 00495 // Asterisk ##### 00496 sscanf(lineStart, "Proxy-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", 00497 realm, nonce) == 2 || 00498 // Cisco ATA ##### 00499 sscanf(lineStart, "Proxy-Authenticate: Digest algorithm=MD5,domain=\"%*[^\"]\",nonce=\"%[^\"]\", realm=\"%[^\"]\"", 00500 nonce, realm) == 2) { 00501 fWorkingAuthenticator->setRealmAndNonce(realm, nonce); 00502 foundAuthenticateHeader = True; 00503 } 00504 delete[] realm; delete[] nonce; 00505 if (foundAuthenticateHeader) break; 00506 } 00507 } 00508 envir().setResultMsg("cannot handle INVITE response: ", firstLine); 00509 break; 00510 } 00511 00512 // Skip every subsequent header line, until we see a blank line. 00513 // While doing so, check for "To:" and "Content-Length:" lines. 00514 // The remaining data is assumed to be the SDP descriptor that we want. 00515 // We should really do some more checking on the headers here - e.g., to 00516 // check for "Content-type: application/sdp", "CSeq", etc. ##### 00517 int contentLength = -1; 00518 char* lineStart; 00519 while (1) { 00520 lineStart = nextLineStart; 00521 if (lineStart == NULL) break; 00522 00523 nextLineStart = getLine(lineStart); 00524 if (lineStart[0] == '\0') break; // this is a blank line 00525 00526 char* toTagStr = strDupSize(lineStart); 00527 if (sscanf(lineStart, "To:%*[^;]; tag=%s", toTagStr) == 1) { 00528 delete[] (char*)fToTagStr; fToTagStr = strDup(toTagStr); 00529 fToTagStrSize = strlen(fToTagStr); 00530 } 00531 delete[] toTagStr; 00532 00533 if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1 00534 || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) { 00535 if (contentLength < 0) { 00536 envir().setResultMsg("Bad \"Content-Length:\" header: \"", 00537 lineStart, "\""); 00538 break; 00539 } 00540 } 00541 } 00542 00543 // We're now at the end of the response header lines 00544 if (lineStart == NULL) { 00545 envir().setResultMsg("no content following header lines: ", readBuf); 00546 break; 00547 } 00548 00549 // Use the remaining data as the SDP descr, but first, check 00550 // the "Content-Length:" header (if any) that we saw. We may need to 00551 // read more data, or we may have extraneous data in the buffer. 00552 char* bodyStart = nextLineStart; 00553 if (bodyStart != NULL && contentLength >= 0) { 00554 // We saw a "Content-Length:" header 00555 unsigned numBodyBytes = &readBuf[bytesRead] - bodyStart; 00556 if (contentLength > (int)numBodyBytes) { 00557 // We need to read more data. First, make sure we have enough 00558 // space for it: 00559 unsigned numExtraBytesNeeded = contentLength - numBodyBytes; 00560 #ifdef USING_TCP 00561 // THIS CODE WORKS ONLY FOR TCP: ##### 00562 unsigned remainingBufferSize 00563 = readBufSize - (bytesRead + (readBuf - readBuffer)); 00564 if (numExtraBytesNeeded > remainingBufferSize) { 00565 char tmpBuf[200]; 00566 sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n", 00567 readBufSize, contentLength, 00568 readBufSize + numExtraBytesNeeded - remainingBufferSize); 00569 envir().setResultMsg(tmpBuf); 00570 break; 00571 } 00572 00573 // Keep reading more data until we have enough: 00574 if (fVerbosityLevel >= 1) { 00575 envir() << "Need to read " << numExtraBytesNeeded 00576 << " extra bytes\n"; 00577 } 00578 while (numExtraBytesNeeded > 0) { 00579 char* ptr = &readBuf[bytesRead]; 00580 unsigned bytesRead2; 00581 struct sockaddr_in fromAddr; 00582 Boolean readSuccess 00583 = fOurSocket->handleRead((unsigned char*)ptr, 00584 numExtraBytesNeeded, 00585 bytesRead2, fromAddr); 00586 if (!readSuccess) break; 00587 ptr[bytesRead2] = '\0'; 00588 if (fVerbosityLevel >= 1) { 00589 envir() << "Read " << bytesRead2 00590 << " extra bytes: " << ptr << "\n"; 00591 } 00592 00593 bytesRead += bytesRead2; 00594 numExtraBytesNeeded -= bytesRead2; 00595 } 00596 #endif 00597 if (numExtraBytesNeeded > 0) break; // one of the reads failed 00598 } 00599 00600 bodyStart[contentLength] = '\0'; // trims any extra data 00601 delete[] fInviteSDPDescriptionReturned; fInviteSDPDescriptionReturned = strDup(bodyStart); 00602 } 00603 } while (0); 00604 00605 return responseCode; 00606 }
| unsigned SIPClient::getResponse | ( | char *& | responseBuffer, | |
| unsigned | responseBufferSize | |||
| ) | [private] |
Definition at line 891 of file SIPClient.cpp.
References Medium::envir(), False, fOurSocket, Groupsock::handleRead(), UsageEnvironment::setResultMsg(), and True.
Referenced by getResponseCode().
00892 { 00893 if (responseBufferSize == 0) return 0; // just in case... 00894 responseBuffer[0] = '\0'; // ditto 00895 00896 // Keep reading data from the socket until we see "\r\n\r\n" (except 00897 // at the start), or until we fill up our buffer. 00898 // Don't read any more than this. 00899 char* p = responseBuffer; 00900 Boolean haveSeenNonCRLF = False; 00901 int bytesRead = 0; 00902 while (bytesRead < (int)responseBufferSize) { 00903 unsigned bytesReadNow; 00904 struct sockaddr_in fromAddr; 00905 unsigned char* toPosn = (unsigned char*)(responseBuffer+bytesRead); 00906 Boolean readSuccess 00907 = fOurSocket->handleRead(toPosn, responseBufferSize-bytesRead, 00908 bytesReadNow, fromAddr); 00909 if (!readSuccess || bytesReadNow == 0) { 00910 envir().setResultMsg("SIP response was truncated"); 00911 break; 00912 } 00913 bytesRead += bytesReadNow; 00914 00915 // Check whether we have "\r\n\r\n": 00916 char* lastToCheck = responseBuffer+bytesRead-4; 00917 if (lastToCheck < responseBuffer) continue; 00918 for (; p <= lastToCheck; ++p) { 00919 if (haveSeenNonCRLF) { 00920 if (*p == '\r' && *(p+1) == '\n' && 00921 *(p+2) == '\r' && *(p+3) == '\n') { 00922 responseBuffer[bytesRead] = '\0'; 00923 00924 // Before returning, trim any \r or \n from the start: 00925 while (*responseBuffer == '\r' || *responseBuffer == '\n') { 00926 ++responseBuffer; 00927 --bytesRead; 00928 } 00929 return bytesRead; 00930 } 00931 } else { 00932 if (*p != '\r' && *p != '\n') { 00933 haveSeenNonCRLF = True; 00934 } 00935 } 00936 } 00937 } 00938 00939 return 0; 00940 }
| Boolean SIPClient::parseResponseCode | ( | char const * | line, | |
| unsigned & | responseCode | |||
| ) | [private] |
Definition at line 942 of file SIPClient.cpp.
References Medium::envir(), False, UsageEnvironment::setResultMsg(), and True.
Referenced by getResponseCode().
00943 { 00944 if (sscanf(line, "%*s%u", &responseCode) != 1) { 00945 envir().setResultMsg("no response code in line: \"", line, "\""); 00946 return False; 00947 } 00948 00949 return True; 00950 }
| Boolean Medium::lookupByName | ( | UsageEnvironment & | env, | |
| char const * | mediumName, | |||
| Medium *& | resultMedium | |||
| ) | [static, inherited] |
Definition at line 41 of file Media.cpp.
References env, False, MediaLookupTable::lookup(), NULL, MediaLookupTable::ourMedia(), UsageEnvironment::setResultMsg(), and True.
Referenced by ServerMediaSession::lookupByName(), RTSPServer::lookupByName(), RTSPClient::lookupByName(), RTCPInstance::lookupByName(), MediaSource::lookupByName(), MediaSink::lookupByName(), MediaSession::lookupByName(), and DarwinInjector::lookupByName().
00042 { 00043 resultMedium = MediaLookupTable::ourMedia(env)->lookup(mediumName); 00044 if (resultMedium == NULL) { 00045 env.setResultMsg("Medium ", mediumName, " does not exist"); 00046 return False; 00047 } 00048 00049 return True; 00050 }
| void Medium::close | ( | UsageEnvironment & | env, | |
| char const * | mediumName | |||
| ) | [static, inherited] |
Definition at line 52 of file Media.cpp.
References env, MediaLookupTable::ourMedia(), and MediaLookupTable::remove().
Referenced by afterPlaying(), Medium::close(), closeMediaSinks(), OnDemandServerMediaSubsession::closeStreamSource(), continueAfterTEARDOWN(), WAVAudioFileSource::createNew(), QuickTimeFileSink::createNew(), QCELPAudioRTPSource::createNew(), MP3FileSource::createNew(), AVIFileSink::createNew(), AMRAudioRTPSource::createNew(), WAVAudioFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), MediaSubsession::deInitiate(), ServerMediaSession::deleteAllSubsessions(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), MediaSubsession::initiate(), MPEG1or2ProgramStreamFileDuration(), MPEG1or2Demux::noteElementaryStreamDeletion(), ByteStreamMultiFileSource::onSourceClosure1(), StreamState::reclaim(), RTSPServer::removeServerMediaSession(), ProxyServerMediaSession::resetDESCRIBEState(), OnDemandServerMediaSubsession::sdpLines(), shutdownStream(), subsessionAfterPlaying(), ClientTrickPlayState::updateStateOnScaleChange(), AMRDeinterleaver::~AMRDeinterleaver(), ByteStreamMultiFileSource::~ByteStreamMultiFileSource(), DarwinInjector::~DarwinInjector(), FramedFilter::~FramedFilter(), H264VideoRTPSink::~H264VideoRTPSink(), InputESSourceRecord::~InputESSourceRecord(), MatroskaFileParser::~MatroskaFileParser(), MatroskaFileServerDemux::~MatroskaFileServerDemux(), MPEG1or2Demux::~MPEG1or2Demux(), MPEG1or2FileServerDemux::~MPEG1or2FileServerDemux(), MPEG2TransportFileServerMediaSubsession::~MPEG2TransportFileServerMediaSubsession(), MPEG2TransportStreamFromPESSource::~MPEG2TransportStreamFromPESSource(), ProxyServerMediaSession::~ProxyServerMediaSession(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::~RTSPClientConnectionSupportingHTTPStreaming(), ServerMediaSubsession::~ServerMediaSubsession(), StreamClientState::~StreamClientState(), StreamReplicator::~StreamReplicator(), and T140TextRTPSink::~T140TextRTPSink().
00052 { 00053 MediaLookupTable::ourMedia(env)->remove(name); 00054 }
| void Medium::close | ( | Medium * | medium | ) | [static, inherited] |
Definition at line 56 of file Media.cpp.
References Medium::close(), Medium::envir(), Medium::name(), and NULL.
00056 { 00057 if (medium == NULL) return; 00058 00059 close(medium->envir(), medium->name()); 00060 }
| UsageEnvironment& Medium::envir | ( | ) | const [inline, inherited] |
Definition at line 59 of file Media.hh.
References Medium::fEnviron.
Referenced by QuickTimeFileSink::addArbitraryString(), FileSink::addData(), RTCPInstance::addStreamSocket(), MPEG2IFrameIndexFromTransportStream::addToTail(), StreamParser::afterGettingBytes1(), DummySink::afterGettingFrame(), TCPStreamSink::afterGettingFrame(), T140IdleFilter::afterGettingFrame(), FileSink::afterGettingFrame(), MultiFramedRTPSink::afterGettingFrame1(), InputESSourceRecord::afterGettingFrame1(), MPEG2TransportStreamFramer::afterGettingFrame1(), MPEG2IFrameIndexFromTransportStream::afterGettingFrame1(), H264VideoStreamDiscreteFramer::afterGettingFrame1(), BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), H264VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoStreamParser::analyzeVOLHeader(), announceStream(), RTSPServer::RTSPClientConnection::changeClientInputSocket(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), H264VideoFileServerMediaSubsession::checkForAuxSDPLine1(), Medium::close(), ProxyServerMediaSubsession::closeStreamSource(), MPEG2IFrameIndexFromTransportStream::compactParseBuffer(), RTSPClient::connectionHandler1(), RTSPClient::connectToServer(), ProxyServerMediaSession::continueAfterDESCRIBE(), ProxyRTSPClient::continueAfterLivenessCommand(), ProxyRTSPClient::continueAfterSETUP(), T140TextRTPSink::continuePlaying(), QuickTimeFileSink::continuePlaying(), H264VideoRTPSink::continuePlaying(), AVIFileSink::continuePlaying(), VP8VideoMatroskaFileServerMediaSubsession::createNewRTPSink(), VorbisAudioMatroskaFileServerMediaSubsession::createNewRTPSink(), T140TextMatroskaFileServerMediaSubsession::createNewRTPSink(), ProxyServerMediaSubsession::createNewRTPSink(), MPEG4VideoFileServerMediaSubsession::createNewRTPSink(), MPEG2TransportUDPServerMediaSubsession::createNewRTPSink(), MPEG2TransportFileServerMediaSubsession::createNewRTPSink(), MPEG1or2VideoFileServerMediaSubsession::createNewRTPSink(), MPEG1or2DemuxedServerMediaSubsession::createNewRTPSink(), MP3AudioFileServerMediaSubsession::createNewRTPSink(), H264VideoFileServerMediaSubsession::createNewRTPSink(), H263plusVideoFileServerMediaSubsession::createNewRTPSink(), DVVideoFileServerMediaSubsession::createNewRTPSink(), AMRAudioFileServerMediaSubsession::createNewRTPSink(), ADTSAudioFileServerMediaSubsession::createNewRTPSink(), AC3AudioMatroskaFileServerMediaSubsession::createNewRTPSink(), AC3AudioFileServerMediaSubsession::createNewRTPSink(), AACAudioMatroskaFileServerMediaSubsession::createNewRTPSink(), ProxyServerMediaSubsession::createNewStreamSource(), MPEG4VideoFileServerMediaSubsession::createNewStreamSource(), MPEG2TransportUDPServerMediaSubsession::createNewStreamSource(), MPEG2TransportFileServerMediaSubsession::createNewStreamSource(), MPEG1or2VideoFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), MP3AudioFileServerMediaSubsession::createNewStreamSource(), H264VideoMatroskaFileServerMediaSubsession::createNewStreamSource(), H264VideoFileServerMediaSubsession::createNewStreamSource(), H263plusVideoFileServerMediaSubsession::createNewStreamSource(), DVVideoFileServerMediaSubsession::createNewStreamSource(), AMRAudioFileServerMediaSubsession::createNewStreamSource(), ADTSAudioFileServerMediaSubsession::createNewStreamSource(), AC3AudioFileServerMediaSubsession::createNewStreamSource(), AMRDeinterleavingBuffer::deliverIncomingFrame(), MPEG2IFrameIndexFromTransportStream::deliverIndexRecord(), SegmentQueue::dequeue(), DeviceSource::DeviceSource(), WAVAudioFileSource::doGetNextFrame(), T140IdleFilter::doGetNextFrame(), MPEG2TransportStreamMultiplexor::doGetNextFrame(), MPEG2IFrameIndexFromTransportStream::doGetNextFrame(), MP3FileSource::doGetNextFrame(), H264FUAFragmenter::doGetNextFrame(), ByteStreamMultiFileSource::doGetNextFrame(), ByteStreamFileSource::doGetNextFrame(), BasicUDPSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), MP3FileSource::doGetNextFrame1(), ADUFromMP3Source::doGetNextFrame1(), doInviteStateMachine(), WAVAudioFileSource::doReadFromFile(), ByteStreamFileSource::doReadFromFile(), MPEG1or2VideoRTPSink::doSpecialFrameHandling(), MP3ADURTPSink::doSpecialFrameHandling(), H263plusVideoRTPSink::doSpecialFrameHandling(), WAVAudioFileSource::doStopGettingFrames(), T140IdleFilter::doStopGettingFrames(), MultiFramedRTPSource::doStopGettingFrames(), FramedSource::doStopGettingFrames(), ByteStreamFileSource::doStopGettingFrames(), BasicUDPSource::doStopGettingFrames(), SegmentQueue::enqueueNewSegment(), StreamParser::ensureValidBytes1(), MediaSubsession::env(), SubsessionIOState::envir(), RTSPServer::RTSPClientSession::envir(), RTSPServer::RTSPClientConnection::envir(), RTPInterface::envir(), AVISubsessionIOState::envir(), ServerMediaSession::generateSDPDescription(), RTPSource::getAttributes(), MP3FileSource::getAttributes(), MP3ADUTranscoder::getAttributes(), MediaSource::getAttributes(), MPEG4VideoFileServerMediaSubsession::getAuxSDPLine(), H264VideoFileServerMediaSubsession::getAuxSDPLine(), getMPEG1or2TimeCode(), FramedSource::getNextFrame(), getOptions(), DVVideoStreamFramer::getProfile(), getResponse(), getResponseCode(), getSDPDescription(), OnDemandServerMediaSubsession::getStreamParameters(), RTSPClient::handleAlternativeRequestByte1(), RTSPClient::handleGET_PARAMETERResponse(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), RTSPClient::handleIncomingRequest(), RTSPClient::handlePLAYResponse(), RTSPClient::handleRequestError(), RTSPClient::handleResponseBytes(), RTSPClient::handleSETUPResponse(), RTSPServer::incomingConnectionHandler(), RTSPClient::incomingDataHandler1(), RTCPInstance::incomingReportHandler1(), MP3FileSource::initializeStream(), MediaSession::initializeWithSDP(), MediaSession::initiateByMediaType(), invite1(), DynamicRTSPServer::lookupServerMediaSession(), MatroskaDemux::MatroskaDemux(), MatroskaFile::MatroskaFile(), MPEG4GenericRTPSource::MPEG4GenericRTPSource(), MultiFramedRTPSource::networkReadHandler1(), MatroskaDemux::newDemuxedTrack(), MPEG1or2FileServerDemux::newElementaryStream(), MPEG1or2Demux::newElementaryStream(), MPEG4GenericBufferedPacket::nextEnclosedFrameSize(), AMRBufferedPacket::nextEnclosedFrameSize(), T140IdleFilter::onSourceClosure(), RTSPClient::openConnection(), MPEG2TransportStreamIndexFile::openFid(), MPEG2IFrameIndexFromTransportStream::parseFrame(), AC3AudioStreamParser::parseFrame(), MPEGProgramStreamParser::parsePackHeader(), MPEGProgramStreamParser::parsePESPacket(), parseResponseCode(), MediaSession::parseSDPLine(), MPEG1or2VideoStreamParser::parseSlice(), MatroskaFileParser::parseStartOfFile(), MPEGProgramStreamParser::parseSystemHeader(), MPEG4VideoStreamParser::parseVideoObjectLayer(), MPEG4VideoStreamParser::parseVideoObjectPlane(), MPEG4VideoStreamParser::parseVisualObject(), TCPStreamSink::processBuffer(), processURL(), AC3AudioStreamParser::readAndSaveAFrame(), MPEG1or2Demux::registerReadInterest(), RTCPInstance::reschedule(), RTSPClient::resendCommand(), ProxyRTSPClient::reset(), RTSPClient::resetTCPSockets(), RTSPClient::responseHandlerForHTTP_GET1(), RTSPServer::rtspURLPrefix(), RTCPInstance::schedule(), ProxyRTSPClient::scheduleDESCRIBECommand(), ProxyRTSPClient::scheduleLivenessCommand(), OnDemandServerMediaSubsession::sdpLines(), sendACK(), sendBYE(), sendINVITE(), MultiFramedRTPSink::sendPacketIfNecessary(), sendRequest(), RTSPClient::sendRequest(), DarwinInjector::setDestination(), RTSPClient::setupHTTPTunneling1(), setupNextSubsession(), RTSPServer::setUpTunnelingOverHTTP(), QuickTimeFileSink::setWord(), AVIFileSink::setWord(), QuickTimeFileSink::setWord64(), shutdownStream(), SIPClient(), TCPStreamSink::socketWritableHandler1(), AMRAudioRTPSink::sourceIsCompatibleWithUs(), QuickTimeFileSink::startPlaying(), StreamState::startPlaying(), MediaSink::startPlaying(), AVIFileSink::startPlaying(), startPlayingSession(), PassiveServerMediaSubsession::startStream(), MediaSink::stopPlaying(), ProxyServerMediaSubsession::subsessionByeHandler(), tearDownSession(), timerAHandler(), timerBHandler(), timerDHandler(), ClientTrickPlayState::updateStateOnScaleChange(), MPEG2TransportStreamFramer::updateTSPacketDurationEstimate(), BasicUDPSource::~BasicUDPSource(), ByteStreamFileSource::~ByteStreamFileSource(), DeviceSource::~DeviceSource(), ProxyServerMediaSession::~ProxyServerMediaSession(), ProxyServerMediaSubsession::~ProxyServerMediaSubsession(), RTSPServer::~RTSPServer(), StreamClientState::~StreamClientState(), T140IdleFilter::~T140IdleFilter(), and WAVAudioFileSource::~WAVAudioFileSource().
00059 {return fEnviron;}
| char const* Medium::name | ( | ) | const [inline, inherited] |
Definition at line 61 of file Media.hh.
References Medium::fMediumName.
Referenced by QuickTimeFileSink::addAtom_hdlr2(), Medium::close(), MP3ADUTranscoder::createNew(), MP3FromADUSource::createNew(), ADUFromMP3Source::createNew(), and MP3FileSource::initializeStream().
00061 {return fMediumName;}
| Boolean Medium::isSource | ( | ) | const [virtual, inherited] |
Reimplemented in MediaSource.
Definition at line 62 of file Media.cpp.
References False.
Referenced by MediaSource::lookupByName().
00062 { 00063 return False; // default implementation 00064 }
| Boolean Medium::isSink | ( | ) | const [virtual, inherited] |
| Boolean Medium::isRTCPInstance | ( | ) | const [virtual, inherited] |
Reimplemented in RTCPInstance.
Definition at line 70 of file Media.cpp.
References False.
Referenced by RTCPInstance::lookupByName().
00070 { 00071 return False; // default implementation 00072 }
| Boolean Medium::isRTSPClient | ( | ) | const [virtual, inherited] |
Reimplemented in RTSPClient.
Definition at line 74 of file Media.cpp.
References False.
Referenced by RTSPClient::lookupByName().
00074 { 00075 return False; // default implementation 00076 }
| Boolean Medium::isRTSPServer | ( | ) | const [virtual, inherited] |
Reimplemented in RTSPServer.
Definition at line 78 of file Media.cpp.
References False.
Referenced by RTSPServer::lookupByName().
00078 { 00079 return False; // default implementation 00080 }
| Boolean Medium::isMediaSession | ( | ) | const [virtual, inherited] |
Reimplemented in MediaSession.
Definition at line 82 of file Media.cpp.
References False.
Referenced by MediaSession::lookupByName().
00082 { 00083 return False; // default implementation 00084 }
| Boolean Medium::isServerMediaSession | ( | ) | const [virtual, inherited] |
Reimplemented in ServerMediaSession.
Definition at line 86 of file Media.cpp.
References False.
Referenced by ServerMediaSession::lookupByName().
00086 { 00087 return False; // default implementation 00088 }
| Boolean Medium::isDarwinInjector | ( | ) | const [virtual, inherited] |
Reimplemented in DarwinInjector.
Definition at line 90 of file Media.cpp.
References False.
Referenced by DarwinInjector::lookupByName().
00090 { 00091 return False; // default implementation 00092 }
| TaskToken& Medium::nextTask | ( | ) | [inline, protected, inherited] |
Definition at line 78 of file Media.hh.
References Medium::fNextTask.
Referenced by BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), H264VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), H264VideoFileServerMediaSubsession::checkForAuxSDPLine1(), MP3FileSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), WAVAudioFileSource::doReadFromFile(), ByteStreamFileSource::doReadFromFile(), MultiFramedRTPSource::doStopGettingFrames(), FramedSource::doStopGettingFrames(), ByteStreamFileSource::doStopGettingFrames(), RTCPInstance::reschedule(), RTCPInstance::schedule(), MultiFramedRTPSink::sendPacketIfNecessary(), and MediaSink::stopPlaying().
00078 { 00079 return fNextTask; 00080 }
friend class MediaLookupTable [friend, inherited] |
TaskToken SIPClient::fTimerA [private] |
TaskToken SIPClient::fTimerB [private] |
TaskToken SIPClient::fTimerD [private] |
unsigned const SIPClient::fT1 [private] |
unsigned SIPClient::fTimerALen [private] |
Definition at line 97 of file SIPClient.hh.
Referenced by doInviteStateMachine(), invite1(), and timerAHandler().
unsigned SIPClient::fTimerACount [private] |
unsigned char SIPClient::fDesiredAudioRTPPayloadFormat [private] |
char* SIPClient::fMIMESubtype [private] |
Definition at line 111 of file SIPClient.hh.
Referenced by invite1(), SIPClient(), and ~SIPClient().
unsigned SIPClient::fMIMESubtypeSize [private] |
int SIPClient::fVerbosityLevel [private] |
Definition at line 113 of file SIPClient.hh.
Referenced by getResponseCode(), sendRequest(), timerAHandler(), timerBHandler(), and timerDHandler().
unsigned SIPClient::fCSeq [private] |
char const* SIPClient::fApplicationName [private] |
Definition at line 115 of file SIPClient.hh.
Referenced by invite1(), reset(), SIPClient(), and ~SIPClient().
unsigned SIPClient::fApplicationNameSize [private] |
char const* SIPClient::fOurAddressStr [private] |
Definition at line 117 of file SIPClient.hh.
Referenced by invite1(), sendACK(), sendBYE(), SIPClient(), and ~SIPClient().
unsigned SIPClient::fOurAddressStrSize [private] |
Definition at line 118 of file SIPClient.hh.
Referenced by invite1(), sendACK(), sendBYE(), and SIPClient().
portNumBits SIPClient::fOurPortNum [private] |
Definition at line 119 of file SIPClient.hh.
Referenced by invite1(), sendACK(), sendBYE(), and SIPClient().
Groupsock* SIPClient::fOurSocket [private] |
Definition at line 120 of file SIPClient.hh.
Referenced by getResponse(), getResponseCode(), invite1(), processURL(), sendRequest(), setProxyServer(), SIPClient(), and ~SIPClient().
char* SIPClient::fUserAgentHeaderStr [private] |
Definition at line 121 of file SIPClient.hh.
Referenced by invite1(), SIPClient(), and ~SIPClient().
unsigned SIPClient::fUserAgentHeaderStrSize [private] |
char const* SIPClient::fURL [private] |
unsigned SIPClient::fURLSize [private] |
struct in_addr SIPClient::fServerAddress [read, private] |
Definition at line 127 of file SIPClient.hh.
Referenced by processURL(), reset(), and setProxyServer().
portNumBits SIPClient::fServerPortNum [private] |
Definition at line 128 of file SIPClient.hh.
Referenced by processURL(), reset(), and setProxyServer().
portNumBits SIPClient::fClientStartPortNum [private] |
unsigned SIPClient::fCallId [private] |
unsigned SIPClient::fFromTag [private] |
char const* SIPClient::fToTagStr [private] |
Definition at line 131 of file SIPClient.hh.
Referenced by getResponseCode(), reset(), sendACK(), and sendBYE().
unsigned SIPClient::fToTagStrSize [private] |
Definition at line 132 of file SIPClient.hh.
Referenced by getResponseCode(), reset(), sendACK(), and sendBYE().
Authenticator SIPClient::fValidAuthenticator [private] |
Definition at line 133 of file SIPClient.hh.
Referenced by invite1(), inviteWithPassword(), and reset().
char const* SIPClient::fUserName [private] |
Definition at line 134 of file SIPClient.hh.
Referenced by invite1(), inviteWithPassword(), reset(), sendACK(), and sendBYE().
unsigned SIPClient::fUserNameSize [private] |
Definition at line 135 of file SIPClient.hh.
Referenced by invite1(), inviteWithPassword(), reset(), sendACK(), and sendBYE().
char* SIPClient::fInviteSDPDescription [private] |
Definition at line 137 of file SIPClient.hh.
Referenced by doInviteStateTerminated(), invite1(), and reset().
char* SIPClient::fInviteSDPDescriptionReturned [private] |
Definition at line 138 of file SIPClient.hh.
Referenced by doInviteStateTerminated(), getInviteSdpReply(), and getResponseCode().
char* SIPClient::fInviteCmd [private] |
unsigned SIPClient::fInviteCmdSize [private] |
Authenticator* SIPClient::fWorkingAuthenticator [private] |
Definition at line 141 of file SIPClient.hh.
Referenced by getResponseCode(), invite1(), and reset().
Definition at line 142 of file SIPClient.hh.
Referenced by doInviteStateMachine(), doInviteStateTerminated(), and invite1().
char SIPClient::fEventLoopStopFlag [private] |
Definition at line 143 of file SIPClient.hh.
Referenced by doInviteStateTerminated(), and invite1().
1.5.2