⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sipclient.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	// "*fWorkingAuthenticator" using the contents of a following	// "Proxy-Authenticate:" line.  (Once we compute a 'response' for	// "fWorkingAuthenticator", it can be used in a subsequent request	// - that will hopefully succeed.)	char* lineStart;	while (1) {	  lineStart = nextLineStart;	  if (lineStart == NULL) break;	  nextLineStart = getLine(lineStart);	  if (lineStart[0] == '\0') break; // this is a blank line	  char* realm = strDupSize(lineStart);	  char* nonce = strDupSize(lineStart);	  // ##### Check for the format of "Proxy-Authenticate:" lines from	  // ##### known server types.	  // ##### This is a crock! We should make the parsing more general          Boolean foundAuthenticateHeader = False;	  if (	      // Asterisk #####	      sscanf(lineStart, "Proxy-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"",		     realm, nonce) == 2 ||	      // Cisco ATA #####	      sscanf(lineStart, "Proxy-Authenticate: Digest algorithm=MD5,domain=\"%*[^\"]\",nonce=\"%[^\"]\", realm=\"%[^\"]\"",		     nonce, realm) == 2) {            fWorkingAuthenticator->setRealmAndNonce(realm, nonce);            foundAuthenticateHeader = True;          }          delete[] realm; delete[] nonce;          if (foundAuthenticateHeader) break;	}       }      envir().setResultMsg("cannot handle INVITE response: ", firstLine);      break;    }    // Skip every subsequent header line, until we see a blank line.    // While doing so, check for "To:" and "Content-Length:" lines.    // The remaining data is assumed to be the SDP descriptor that we want.    // We should really do some more checking on the headers here - e.g., to    // check for "Content-type: application/sdp", "CSeq", etc. #####    int contentLength = -1;    char* lineStart;    while (1) {      lineStart = nextLineStart;      if (lineStart == NULL) break;      nextLineStart = getLine(lineStart);      if (lineStart[0] == '\0') break; // this is a blank line      char* toTagStr = strDupSize(lineStart);      if (sscanf(lineStart, "To:%*[^;]; tag=%s", toTagStr) == 1) {	delete[] (char*)fToTagStr; fToTagStr = strDup(toTagStr);	fToTagStrSize = strlen(fToTagStr);      }      delete[] toTagStr;       if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1          || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) {        if (contentLength < 0) {          envir().setResultMsg("Bad \"Content-length:\" header: \"",                               lineStart, "\"");          break;        }      }    }    // We're now at the end of the response header lines    if (lineStart == NULL) {      envir().setResultMsg("no content following header lines: ", readBuf);      break;    }    // Use the remaining data as the SDP descr, but first, check    // the "Content-length:" header (if any) that we saw.  We may need to    // read more data, or we may have extraneous data in the buffer.    char* bodyStart = nextLineStart;    if (contentLength >= 0) {      // We saw a "Content-length:" header      unsigned numBodyBytes = &readBuf[bytesRead] - bodyStart;      if (contentLength > (int)numBodyBytes) {        // We need to read more data.  First, make sure we have enough        // space for it:        unsigned numExtraBytesNeeded = contentLength - numBodyBytes;#ifdef USING_TCP	// THIS CODE WORKS ONLY FOR TCP: #####        unsigned remainingBufferSize          = readBufSize - (bytesRead + (readBuf - readBuffer));        if (numExtraBytesNeeded > remainingBufferSize) {          char tmpBuf[200];          sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-length:\" %d (need a buffer size of >= %d bytes\n",                  readBufSize, contentLength,                  readBufSize + numExtraBytesNeeded - remainingBufferSize);          envir().setResultMsg(tmpBuf);          break;        }        // Keep reading more data until we have enough:        if (fVerbosityLevel >= 1) {          envir() << "Need to read " << numExtraBytesNeeded		  << " extra bytes\n";        }        while (numExtraBytesNeeded > 0) {          char* ptr = &readBuf[bytesRead];	  unsigned bytesRead2;	  struct sockaddr_in fromAddr;	  Boolean readSuccess	    = fOurSocket->handleRead((unsigned char*)ptr,				     numExtraBytesNeeded,				     bytesRead2, fromAddr);          if (!readSuccess) break;          ptr[bytesRead2] = '\0';          if (fVerbosityLevel >= 1) {            envir() << "Read " << bytesRead2		    << " extra bytes: " << ptr << "\n";          }          bytesRead += bytesRead2;          numExtraBytesNeeded -= bytesRead2;        }#endif        if (numExtraBytesNeeded > 0) break; // one of the reads failed      }      bodyStart[contentLength] = '\0'; // trims any extra data    }  } while (0);  return responseCode;}char* SIPClient::inviteWithPassword(char const* url, char const* username,				    char const* password) {  delete[] (char*)fUserName; fUserName = strDup(username);  fUserNameSize = strlen(fUserName);  Authenticator authenticator;  authenticator.setUsernameAndPassword(username, password);  char* inviteResult = invite(url, &authenticator);  if (inviteResult != NULL) {    // We are already authorized    return inviteResult;  }  // The "realm" and "nonce" fields should have been filled in:  if (authenticator.realm() == NULL || authenticator.nonce() == NULL) {    // We haven't been given enough information to try again, so fail:    return NULL;  }  // Try again (but with the same CallId):  inviteResult = invite1(&authenticator);  if (inviteResult != NULL) {    // The authenticator worked, so use it in future requests:    fValidAuthenticator = authenticator;  }  return inviteResult;}Boolean SIPClient::sendACK() {  char* cmd = NULL;  do {    char* const cmdFmt =      "ACK %s SIP/2.0\r\n"      "From: %s <sip:%s@%s>;tag=%u\r\n"      "Via: SIP/2.0/UDP %s:%u\r\n"      "To: %s;tag=%s\r\n"      "Call-ID: %u@%s\r\n"      "CSeq: %d ACK\r\n"      "Content-length: 0\r\n\r\n";    unsigned cmdSize = strlen(cmdFmt)      + fURLSize      + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */      + fOurAddressStrSize + 5 /* max port len */      + fURLSize + fToTagStrSize      + 20 + fOurAddressStrSize      + 20;    cmd = new char[cmdSize];    sprintf(cmd, cmdFmt,	    fURL,	    fUserName, fUserName, fOurAddressStr, fFromTag,	    fOurAddressStr, fOurPortNum,	    fURL, fToTagStr,	    fCallId, fOurAddressStr,	    fCSeq /* note: it's the same as before; not incremented */);        if (!sendRequest(cmd, strlen(cmd))) {      envir().setResultErrMsg("ACK send() failed: ");      break;    }    delete[] cmd;    return True;  } while (0);  delete[] cmd;  return False;}Boolean SIPClient::sendBYE() {  // NOTE: This should really be retransmitted, for reliability #####  char* cmd = NULL;  do {    char* const cmdFmt =      "BYE %s SIP/2.0\r\n"      "From: %s <sip:%s@%s>;tag=%u\r\n"      "Via: SIP/2.0/UDP %s:%u\r\n"      "To: %s;tag=%s\r\n"      "Call-ID: %u@%s\r\n"      "CSeq: %d ACK\r\n"      "Content-length: 0\r\n\r\n";    unsigned cmdSize = strlen(cmdFmt)      + fURLSize      + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */      + fOurAddressStrSize + 5 /* max port len */      + fURLSize + fToTagStrSize      + 20 + fOurAddressStrSize      + 20;    cmd = new char[cmdSize];    sprintf(cmd, cmdFmt,	    fURL,	    fUserName, fUserName, fOurAddressStr, fFromTag,	    fOurAddressStr, fOurPortNum,	    fURL, fToTagStr,	    fCallId, fOurAddressStr,	    ++fCSeq);        if (!sendRequest(cmd, strlen(cmd))) {      envir().setResultErrMsg("BYE send() failed: ");      break;    }    delete[] cmd;    return True;  } while (0);  delete[] cmd;  return False;}Boolean SIPClient::processURL(char const* url) {  do {    // If we don't already have a server address/port, then    // get these by parsing the URL:    if (fServerAddress.s_addr == 0) {      NetAddress destAddress;      if (!parseSIPURL(envir(), url, destAddress, fServerPortNum)) break;      fServerAddress.s_addr = *(unsigned*)(destAddress.data());          if (fOurSocket != NULL) {	fOurSocket->changeDestinationParameters(fServerAddress,						fServerPortNum, 255);      }    }    return True;   } while (0);  fInviteStatusCode = 1;  return False;}Boolean SIPClient::parseSIPURL(UsageEnvironment& env, char const* url,			       NetAddress& address,			       portNumBits& portNum) {  do {    // Parse the URL as "sip:<username>@<address>:<port>/<etc>"    // (with ":<port>" and "/<etc>" optional)    // Also, skip over any "<username>[:<password>]@" preceding <address>    char const* prefix = "sip:";    unsigned const prefixLength = 4;    if (_strncasecmp(url, prefix, prefixLength) != 0) {      env.setResultMsg("URL is not of the form \"", prefix, "\"");      break;    }    unsigned const parseBufferSize = 100;    char parseBuffer[parseBufferSize];    unsigned addressStartIndex = prefixLength;    while (url[addressStartIndex] != '\0'	   && url[addressStartIndex++] != '@') {}    char const* from = &url[addressStartIndex];    // Skip over any "<username>[:<password>]@"    char const* from1 = from;    while (*from1 != '\0' && *from1 != '/') {      if (*from1 == '@') {	from = ++from1;	break;      }      ++from1;    }    char* to = &parseBuffer[0];    unsigned i;    for (i = 0; i < parseBufferSize; ++i) {      if (*from == '\0' || *from == ':' || *from == '/') {	// We've completed parsing the address	*to = '\0';	break;      }      *to++ = *from++;    }    if (i == parseBufferSize) {      env.setResultMsg("URL is too long");      break;    }    NetAddressList addresses(parseBuffer);    if (addresses.numAddresses() == 0) {      env.setResultMsg("Failed to find network address for \"",			   parseBuffer, "\"");      break;    }    address = *(addresses.firstAddress());    portNum = 5060; // default value    char nextChar = *from;    if (nextChar == ':') {      int portNumInt;      if (sscanf(++from, "%d", &portNumInt) != 1) {	env.setResultMsg("No port number follows ':'");	break;      }      if (portNumInt < 1 || portNumInt > 65535) {	env.setResultMsg("Bad port number");	break;      }      portNum = (portNumBits)portNumInt;    }    return True;  } while (0);  return False;}Boolean SIPClient::parseSIPURLUsernamePassword(char const* url,					       char*& username,					       char*& password) {  username = password = NULL; // by default  do {    // Parse the URL as "sip:<username>[:<password>]@<whatever>"    char const* prefix = "sip:";    unsigned const prefixLength = 4;    if (_strncasecmp(url, prefix, prefixLength) != 0) break;    // Look for the ':' and '@':    unsigned usernameIndex = prefixLength;    unsigned colonIndex = 0, atIndex = 0;    for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) {      if (url[i] == ':' && colonIndex == 0) {	colonIndex = i;      } else if (url[i] == '@') {        atIndex = i;        break; // we're done      }    }    if (atIndex == 0) break; // no '@' found    char* urlCopy = strDup(url);    urlCopy[atIndex] = '\0';    if (colonIndex > 0) {      urlCopy[colonIndex] = '\0';      password = strDup(&urlCopy[colonIndex+1]);    } else {      password = strDup("");    }    username = strDup(&urlCopy[usernameIndex]);    delete[] urlCopy;    return True;  } while (0);  return False;}char*SIPClient::createAuthenticatorString(Authenticator const* authenticator,				      char const* cmd, char const* url) {  if (authenticator != NULL && authenticator->realm() != NULL      && authenticator->nonce() != NULL && authenticator->username() != NULL      && authenticator->password() != NULL) {    // We've been provided a filled-in authenticator, so use it:    char* const authFmt = "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", response=\"%s\", uri=\"%s\"\r\n";    char const* response = authenticator->computeDigestResponse(cmd, url);    unsigned authBufSize = strlen(authFmt)      + strlen(authenticator->username()) + strlen(authenticator->realm())      + strlen(authenticator->nonce()) + strlen(url) + strlen(response);    char* authenticatorStr = new char[authBufSize];    sprintf(authenticatorStr, authFmt,	    authenticator->username(), authenticator->realm(),	    authenticator->nonce(), response, url);    authenticator->reclaimDigestResponse(response);    return authenticatorStr;  }  return strDup("");}Boolean SIPClient::sendRequest(char const* requestString,			       unsigned requestLength) {  if (fVerbosityLevel >= 1) {    envir() << "Sending request: " << requestString << "\n";  }  // NOTE: We should really check that "requestLength" is not #####  // too large for UDP (see RFC 3261, section 18.1.1) #####  return fOurSocket->output(envir(), 255, (unsigned char*)requestString,			    requestLength);}unsigned SIPClient::getResponse(char*& responseBuffer,				unsigned responseBufferSize) {  if (responseBufferSize == 0) return 0; // just in case...  responseBuffer[0] = '\0'; // ditto  // Keep reading data from the socket until we see "\r\n\r\n" (except  // at the start), or until we fill up our buffer.  // Don't read any more than this.  char* p = responseBuffer;  Boolean haveSeenNonCRLF = False;  int bytesRead = 0;  while (bytesRead < (int)responseBufferSize) {    unsigned bytesReadNow;    struct sockaddr_in fromAddr;    unsigned char* toPosn = (unsigned char*)(responseBuffer+bytesRead);    Boolean readSuccess      = fOurSocket->handleRead(toPosn, responseBufferSize-bytesRead,			       bytesReadNow, fromAddr);    if (!readSuccess || bytesReadNow == 0) {      envir().setResultMsg("SIP response was truncated");      break;    }    bytesRead += bytesReadNow;        // Check whether we have "\r\n\r\n":    char* lastToCheck = responseBuffer+bytesRead-4;    if (lastToCheck < responseBuffer) continue;    for (; p <= lastToCheck; ++p) {      if (haveSeenNonCRLF) {        if (*p == '\r' && *(p+1) == '\n' &&            *(p+2) == '\r' && *(p+3) == '\n') {          responseBuffer[bytesRead] = '\0';          // Before returning, trim any \r or \n from the start:          while (*responseBuffer == '\r' || *responseBuffer == '\n') {            ++responseBuffer;            --bytesRead;          }          return bytesRead;        }      } else {        if (*p != '\r' && *p != '\n') {          haveSeenNonCRLF = True;        }      }    }  }    return 0;}Boolean SIPClient::parseResponseCode(char const* line, 				      unsigned& responseCode) {  if (sscanf(line, "%*s%u", &responseCode) != 1) {    envir().setResultMsg("no response code in line: \"", line, "\"");    return False;  }  return True;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -