00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "SIPClient.hh"
00022 #include "GroupsockHelper.hh"
00023
00024 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
00025 #define _strncasecmp _strnicmp
00026 #else
00027 #define _strncasecmp strncasecmp
00028 #endif
00029
00031
00032 SIPClient* SIPClient
00033 ::createNew(UsageEnvironment& env,
00034 unsigned char desiredAudioRTPPayloadFormat,
00035 char const* mimeSubtype,
00036 int verbosityLevel, char const* applicationName) {
00037 return new SIPClient(env, desiredAudioRTPPayloadFormat, mimeSubtype,
00038 verbosityLevel, applicationName);
00039 }
00040
00041 SIPClient::SIPClient(UsageEnvironment& env,
00042 unsigned char desiredAudioRTPPayloadFormat,
00043 char const* mimeSubtype,
00044 int verbosityLevel, char const* applicationName)
00045 : Medium(env),
00046 fT1(500000 ),
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), fInviteCmd(NULL), fInviteCmdSize(0){
00053 if (mimeSubtype == NULL) mimeSubtype = "";
00054 fMIMESubtype = strDup(mimeSubtype);
00055 fMIMESubtypeSize = strlen(fMIMESubtype);
00056
00057 if (applicationName == NULL) applicationName = "";
00058 fApplicationName = strDup(applicationName);
00059 fApplicationNameSize = strlen(fApplicationName);
00060
00061 struct in_addr ourAddress;
00062 ourAddress.s_addr = ourIPAddress(env);
00063 fOurAddressStr = strDup(our_inet_ntoa(ourAddress));
00064 fOurAddressStrSize = strlen(fOurAddressStr);
00065
00066 fOurSocket = new Groupsock(env, ourAddress, 0, 255);
00067 if (fOurSocket == NULL) {
00068 env << "ERROR: Failed to create socket for addr "
00069 << our_inet_ntoa(ourAddress) << ": "
00070 << env.getResultMsg() << "\n";
00071 }
00072
00073
00074
00075 fOurSocket->output(envir(), 255, (unsigned char*)"", 0);
00076 Port srcPort(0);
00077 getSourcePort(env, fOurSocket->socketNum(), srcPort);
00078 if (srcPort.num() != 0) {
00079 fOurPortNum = ntohs(srcPort.num());
00080 } else {
00081
00082 fOurPortNum = 5060;
00083 delete fOurSocket;
00084 fOurSocket = new Groupsock(env, ourAddress, fOurPortNum, 255);
00085 if (fOurSocket == NULL) {
00086 env << "ERROR: Failed to create socket for addr "
00087 << our_inet_ntoa(ourAddress) << ", port "
00088 << fOurPortNum << ": "
00089 << env.getResultMsg() << "\n";
00090 }
00091 }
00092
00093
00094 char const* formatStr;
00095 unsigned headerSize;
00096
00097
00098 char const* const libName = "LIVE555 Streaming Media v";
00099 char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
00100 char const* libPrefix; char const* libSuffix;
00101 if (applicationName == NULL || applicationName[0] == '\0') {
00102 applicationName = libPrefix = libSuffix = "";
00103 } else {
00104 libPrefix = " (";
00105 libSuffix = ")";
00106 }
00107 formatStr = "User-Agent: %s%s%s%s%s\r\n";
00108 headerSize
00109 = strlen(formatStr) + fApplicationNameSize + strlen(libPrefix)
00110 + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix);
00111 fUserAgentHeaderStr = new char[headerSize];
00112 sprintf(fUserAgentHeaderStr, formatStr,
00113 applicationName, libPrefix, libName, libVersionStr, libSuffix);
00114 fUserAgentHeaderStrSize = strlen(fUserAgentHeaderStr);
00115
00116 reset();
00117 }
00118
00119 SIPClient::~SIPClient() {
00120 reset();
00121
00122 delete[] fUserAgentHeaderStr;
00123 delete fOurSocket;
00124 delete[] (char*)fOurAddressStr;
00125 delete[] (char*)fApplicationName;
00126 delete[] (char*)fMIMESubtype;
00127 }
00128
00129 void SIPClient::reset() {
00130 fWorkingAuthenticator = NULL;
00131 delete[] fInviteCmd; fInviteCmd = NULL; fInviteCmdSize = 0;
00132 delete[] fInviteSDPDescription; fInviteSDPDescription = NULL;
00133
00134 delete[] (char*)fUserName; fUserName = strDup(fApplicationName);
00135 fUserNameSize = strlen(fUserName);
00136
00137 fValidAuthenticator.reset();
00138
00139 delete[] (char*)fToTagStr; fToTagStr = NULL; fToTagStrSize = 0;
00140 fServerPortNum = 0;
00141 fServerAddress.s_addr = 0;
00142 delete[] (char*)fURL; fURL = NULL; fURLSize = 0;
00143 }
00144
00145 void SIPClient::setProxyServer(unsigned proxyServerAddress,
00146 portNumBits proxyServerPortNum) {
00147 fServerAddress.s_addr = proxyServerAddress;
00148 fServerPortNum = proxyServerPortNum;
00149 if (fOurSocket != NULL) {
00150 fOurSocket->changeDestinationParameters(fServerAddress,
00151 fServerPortNum, 255);
00152 }
00153 }
00154
00155 static char* getLine(char* startOfLine) {
00156
00157 for (char* ptr = startOfLine; *ptr != '\0'; ++ptr) {
00158 if (*ptr == '\r' || *ptr == '\n') {
00159
00160 *ptr++ = '\0';
00161 if (*ptr == '\n') ++ptr;
00162 return ptr;
00163 }
00164 }
00165
00166 return NULL;
00167 }
00168
00169 char* SIPClient::invite(char const* url, Authenticator* authenticator) {
00170
00171 fInviteStatusCode = 0;
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;
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_random();
00186 fFromTag = our_random();
00187
00188 return invite1(authenticator);
00189 }
00190
00191 char* SIPClient::invite1(Authenticator* authenticator) {
00192 do {
00193
00194
00195
00196 fValidAuthenticator.reset();
00197 fWorkingAuthenticator = authenticator;
00198 char* authenticatorStr
00199 = createAuthenticatorString(fWorkingAuthenticator, "INVITE", fURL);
00200
00201
00202 char* rtpmapLine;
00203 unsigned rtpmapLineSize;
00204 if (fMIMESubtypeSize > 0) {
00205 char* const rtpmapFmt =
00206 "a=rtpmap:%u %s/8000\r\n";
00207 unsigned rtpmapFmtSize = strlen(rtpmapFmt)
00208 + 3 + fMIMESubtypeSize;
00209 rtpmapLine = new char[rtpmapFmtSize];
00210 sprintf(rtpmapLine, rtpmapFmt,
00211 fDesiredAudioRTPPayloadFormat, fMIMESubtype);
00212 rtpmapLineSize = strlen(rtpmapLine);
00213 } else {
00214
00215 rtpmapLine = strDup("");
00216 rtpmapLineSize = 0;
00217 }
00218 char* 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 + 20 + fOurAddressStrSize
00228 + fApplicationNameSize
00229 + fOurAddressStrSize
00230 + 5 + 3
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 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 "To: %s\r\n"
00248 "Contact: sip:%s@%s:%u\r\n"
00249 "Call-ID: %u@%s\r\n"
00250 "CSeq: %d INVITE\r\n"
00251 "Content-Type: application/sdp\r\n"
00252 "%s"
00253 "%s"
00254 "Content-length: %d\r\n\r\n"
00255 "%s";
00256 unsigned inviteCmdSize = strlen(cmdFmt)
00257 + fURLSize
00258 + 2*fUserNameSize + fOurAddressStrSize + 20
00259 + fOurAddressStrSize + 5
00260 + fURLSize
00261 + fUserNameSize + fOurAddressStrSize + 5
00262 + 20 + fOurAddressStrSize
00263 + 20
00264 + strlen(authenticatorStr)
00265 + fUserAgentHeaderStrSize
00266 + 20
00267 + inviteSDPSize;
00268 delete[] fInviteCmd; fInviteCmd = new char[inviteCmdSize];
00269 sprintf(fInviteCmd, cmdFmt,
00270 fURL,
00271 fUserName, fUserName, fOurAddressStr, fFromTag,
00272 fOurAddressStr, fOurPortNum,
00273 fURL,
00274 fUserName, fOurAddressStr, fOurPortNum,
00275 fCallId, fOurAddressStr,
00276 ++fCSeq,
00277 authenticatorStr,
00278 fUserAgentHeaderStr,
00279 inviteSDPSize,
00280 fInviteSDPDescription);
00281 fInviteCmdSize = strlen(fInviteCmd);
00282 delete[] authenticatorStr;
00283
00284
00285
00286 fInviteClientState = Calling;
00287 fEventLoopStopFlag = 0;
00288 TaskScheduler& sched = envir().taskScheduler();
00289 sched.turnOnBackgroundReadHandling(fOurSocket->socketNum(),
00290 &inviteResponseHandler, this);
00291 fTimerALen = 1*fT1;
00292 fTimerACount = 0;
00293 fTimerA = sched.scheduleDelayedTask(fTimerALen, timerAHandler, this);
00294 fTimerB = sched.scheduleDelayedTask(64*fT1, timerBHandler, this);
00295 fTimerD = NULL;
00296
00297 if (!sendINVITE()) break;
00298
00299
00300 envir().taskScheduler().doEventLoop(&fEventLoopStopFlag);
00301
00302
00303
00304 sched.turnOffBackgroundReadHandling(fOurSocket->socketNum());
00305 sched.unscheduleDelayedTask(fTimerA);
00306 sched.unscheduleDelayedTask(fTimerB);
00307 sched.unscheduleDelayedTask(fTimerD);
00308
00309
00310
00311
00312 if (fInviteSDPDescription != NULL) {
00313 return strDup(fInviteSDPDescription);
00314 }
00315 } while (0);
00316
00317 fInviteStatusCode = 2;
00318 return NULL;
00319 }
00320
00321 void SIPClient::inviteResponseHandler(void* clientData, int ) {
00322 SIPClient* client = (SIPClient*)clientData;
00323 unsigned responseCode = client->getResponseCode();
00324 client->doInviteStateMachine(responseCode);
00325 }
00326
00327
00328 unsigned const timerAFires = 0xAAAAAAAA;
00329 unsigned const timerBFires = 0xBBBBBBBB;
00330 unsigned const timerDFires = 0xDDDDDDDD;
00331
00332 void SIPClient::timerAHandler(void* clientData) {
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 }
00341
00342 void SIPClient::timerBHandler(void* clientData) {
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 }
00351
00352 void SIPClient::timerDHandler(void* clientData) {
00353 SIPClient* client = (SIPClient*)clientData;
00354 if (client->fVerbosityLevel >= 1) {
00355 client->envir() << "TIMER D EXPIRED\n";
00356 }
00357 client->doInviteStateMachine(timerDFires);
00358 }
00359
00360 void SIPClient::doInviteStateMachine(unsigned responseCode) {
00361
00362 TaskScheduler& sched = envir().taskScheduler();
00363 switch (fInviteClientState) {
00364 case Calling: {
00365 if (responseCode == timerAFires) {
00366
00367 fTimerALen *= 2;
00368 fTimerA
00369 = sched.scheduleDelayedTask(fTimerALen, timerAHandler, this);
00370
00371 fInviteClientState = Calling;
00372 if (!sendINVITE()) doInviteStateTerminated(0);
00373 } else {
00374
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
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
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 }
00431
00432 void SIPClient::doInviteStateTerminated(unsigned responseCode) {
00433 fInviteClientState = Terminated;
00434 if (responseCode < 200 || responseCode > 299) {
00435
00436 delete[] fInviteSDPDescription; fInviteSDPDescription = NULL;
00437 }
00438
00439
00440 fEventLoopStopFlag = ~0;
00441 }
00442
00443 Boolean SIPClient::sendINVITE() {
00444 if (!sendRequest(fInviteCmd, fInviteCmdSize)) {
00445 envir().setResultErrMsg("INVITE send() failed: ");
00446 return False;
00447 }
00448 return True;
00449 }
00450
00451 unsigned SIPClient::getResponseCode() {
00452 unsigned responseCode = 0;
00453 do {
00454
00455 unsigned const readBufSize = 10000;
00456 char readBuffer[readBufSize+1]; char* readBuf = readBuffer;
00457
00458 char* firstLine = NULL;
00459 char* nextLineStart = NULL;
00460 unsigned bytesRead = getResponse(readBuf, readBufSize);
00461 if (bytesRead == 0) break;
00462 if (fVerbosityLevel >= 1) {
00463 envir() << "Received INVITE response: " << readBuf << "\n";
00464 }
00465
00466
00467 firstLine = readBuf;
00468 nextLineStart = getLine(firstLine);
00469 if (!parseResponseCode(firstLine, responseCode)) break;
00470
00471 if (responseCode != 200) {
00472 if (responseCode >= 400 && responseCode <= 499
00473 && fWorkingAuthenticator != NULL) {
00474
00475
00476
00477
00478
00479 char* lineStart;
00480 while (1) {
00481 lineStart = nextLineStart;
00482 if (lineStart == NULL) break;
00483
00484 nextLineStart = getLine(lineStart);
00485 if (lineStart[0] == '\0') break;
00486
00487 char* realm = strDupSize(lineStart);
00488 char* nonce = strDupSize(lineStart);
00489
00490
00491
00492 Boolean foundAuthenticateHeader = False;
00493 if (
00494
00495 sscanf(lineStart, "Proxy-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"",
00496 realm, nonce) == 2 ||
00497
00498 sscanf(lineStart, "Proxy-Authenticate: Digest algorithm=MD5,domain=\"%*[^\"]\",nonce=\"%[^\"]\", realm=\"%[^\"]\"",
00499 nonce, realm) == 2) {
00500 fWorkingAuthenticator->setRealmAndNonce(realm, nonce);
00501 foundAuthenticateHeader = True;
00502 }
00503 delete[] realm; delete[] nonce;
00504 if (foundAuthenticateHeader) break;
00505 }
00506 }
00507 envir().setResultMsg("cannot handle INVITE response: ", firstLine);
00508 break;
00509 }
00510
00511
00512
00513
00514
00515
00516 int contentLength = -1;
00517 char* lineStart;
00518 while (1) {
00519 lineStart = nextLineStart;
00520 if (lineStart == NULL) break;
00521
00522 nextLineStart = getLine(lineStart);
00523 if (lineStart[0] == '\0') break;
00524
00525 char* toTagStr = strDupSize(lineStart);
00526 if (sscanf(lineStart, "To:%*[^;]; tag=%s", toTagStr) == 1) {
00527 delete[] (char*)fToTagStr; fToTagStr = strDup(toTagStr);
00528 fToTagStrSize = strlen(fToTagStr);
00529 }
00530 delete[] toTagStr;
00531
00532 if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1
00533 || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) {
00534 if (contentLength < 0) {
00535 envir().setResultMsg("Bad \"Content-length:\" header: \"",
00536 lineStart, "\"");
00537 break;
00538 }
00539 }
00540 }
00541
00542
00543 if (lineStart == NULL) {
00544 envir().setResultMsg("no content following header lines: ", readBuf);
00545 break;
00546 }
00547
00548
00549
00550
00551 char* bodyStart = nextLineStart;
00552 if (bodyStart != NULL && contentLength >= 0) {
00553
00554 unsigned numBodyBytes = &readBuf[bytesRead] - bodyStart;
00555 if (contentLength > (int)numBodyBytes) {
00556
00557
00558 unsigned numExtraBytesNeeded = contentLength - numBodyBytes;
00559 #ifdef USING_TCP
00560
00561 unsigned remainingBufferSize
00562 = readBufSize - (bytesRead + (readBuf - readBuffer));
00563 if (numExtraBytesNeeded > remainingBufferSize) {
00564 char tmpBuf[200];
00565 sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-length:\" %d (need a buffer size of >= %d bytes\n",
00566 readBufSize, contentLength,
00567 readBufSize + numExtraBytesNeeded - remainingBufferSize);
00568 envir().setResultMsg(tmpBuf);
00569 break;
00570 }
00571
00572
00573 if (fVerbosityLevel >= 1) {
00574 envir() << "Need to read " << numExtraBytesNeeded
00575 << " extra bytes\n";
00576 }
00577 while (numExtraBytesNeeded > 0) {
00578 char* ptr = &readBuf[bytesRead];
00579 unsigned bytesRead2;
00580 struct sockaddr_in fromAddr;
00581 Boolean readSuccess
00582 = fOurSocket->handleRead((unsigned char*)ptr,
00583 numExtraBytesNeeded,
00584 bytesRead2, fromAddr);
00585 if (!readSuccess) break;
00586 ptr[bytesRead2] = '\0';
00587 if (fVerbosityLevel >= 1) {
00588 envir() << "Read " << bytesRead2
00589 << " extra bytes: " << ptr << "\n";
00590 }
00591
00592 bytesRead += bytesRead2;
00593 numExtraBytesNeeded -= bytesRead2;
00594 }
00595 #endif
00596 if (numExtraBytesNeeded > 0) break;
00597 }
00598
00599 bodyStart[contentLength] = '\0';
00600 }
00601 } while (0);
00602
00603 return responseCode;
00604 }
00605
00606 char* SIPClient::inviteWithPassword(char const* url, char const* username,
00607 char const* password) {
00608 delete[] (char*)fUserName; fUserName = strDup(username);
00609 fUserNameSize = strlen(fUserName);
00610
00611 Authenticator authenticator;
00612 authenticator.setUsernameAndPassword(username, password);
00613 char* inviteResult = invite(url, &authenticator);
00614 if (inviteResult != NULL) {
00615
00616 return inviteResult;
00617 }
00618
00619
00620 if (authenticator.realm() == NULL || authenticator.nonce() == NULL) {
00621
00622 return NULL;
00623 }
00624
00625
00626 inviteResult = invite1(&authenticator);
00627 if (inviteResult != NULL) {
00628
00629 fValidAuthenticator = authenticator;
00630 }
00631
00632 return inviteResult;
00633 }
00634
00635 Boolean SIPClient::sendACK() {
00636 char* cmd = NULL;
00637 do {
00638 char* const cmdFmt =
00639 "ACK %s SIP/2.0\r\n"
00640 "From: %s <sip:%s@%s>;tag=%u\r\n"
00641 "Via: SIP/2.0/UDP %s:%u\r\n"
00642 "To: %s;tag=%s\r\n"
00643 "Call-ID: %u@%s\r\n"
00644 "CSeq: %d ACK\r\n"
00645 "Content-length: 0\r\n\r\n";
00646 unsigned cmdSize = strlen(cmdFmt)
00647 + fURLSize
00648 + 2*fUserNameSize + fOurAddressStrSize + 20
00649 + fOurAddressStrSize + 5
00650 + fURLSize + fToTagStrSize
00651 + 20 + fOurAddressStrSize
00652 + 20;
00653 cmd = new char[cmdSize];
00654 sprintf(cmd, cmdFmt,
00655 fURL,
00656 fUserName, fUserName, fOurAddressStr, fFromTag,
00657 fOurAddressStr, fOurPortNum,
00658 fURL, fToTagStr,
00659 fCallId, fOurAddressStr,
00660 fCSeq );
00661
00662 if (!sendRequest(cmd, strlen(cmd))) {
00663 envir().setResultErrMsg("ACK send() failed: ");
00664 break;
00665 }
00666
00667 delete[] cmd;
00668 return True;
00669 } while (0);
00670
00671 delete[] cmd;
00672 return False;
00673 }
00674
00675 Boolean SIPClient::sendBYE() {
00676
00677 char* cmd = NULL;
00678 do {
00679 char* const cmdFmt =
00680 "BYE %s SIP/2.0\r\n"
00681 "From: %s <sip:%s@%s>;tag=%u\r\n"
00682 "Via: SIP/2.0/UDP %s:%u\r\n"
00683 "To: %s;tag=%s\r\n"
00684 "Call-ID: %u@%s\r\n"
00685 "CSeq: %d ACK\r\n"
00686 "Content-length: 0\r\n\r\n";
00687 unsigned cmdSize = strlen(cmdFmt)
00688 + fURLSize
00689 + 2*fUserNameSize + fOurAddressStrSize + 20
00690 + fOurAddressStrSize + 5
00691 + fURLSize + fToTagStrSize
00692 + 20 + fOurAddressStrSize
00693 + 20;
00694 cmd = new char[cmdSize];
00695 sprintf(cmd, cmdFmt,
00696 fURL,
00697 fUserName, fUserName, fOurAddressStr, fFromTag,
00698 fOurAddressStr, fOurPortNum,
00699 fURL, fToTagStr,
00700 fCallId, fOurAddressStr,
00701 ++fCSeq);
00702
00703 if (!sendRequest(cmd, strlen(cmd))) {
00704 envir().setResultErrMsg("BYE send() failed: ");
00705 break;
00706 }
00707
00708 delete[] cmd;
00709 return True;
00710 } while (0);
00711
00712 delete[] cmd;
00713 return False;
00714 }
00715
00716 Boolean SIPClient::processURL(char const* url) {
00717 do {
00718
00719
00720 if (fServerAddress.s_addr == 0) {
00721 NetAddress destAddress;
00722 if (!parseSIPURL(envir(), url, destAddress, fServerPortNum)) break;
00723 fServerAddress.s_addr = *(unsigned*)(destAddress.data());
00724
00725 if (fOurSocket != NULL) {
00726 fOurSocket->changeDestinationParameters(fServerAddress,
00727 fServerPortNum, 255);
00728 }
00729 }
00730
00731 return True;
00732 } while (0);
00733
00734 fInviteStatusCode = 1;
00735 return False;
00736 }
00737
00738 Boolean SIPClient::parseSIPURL(UsageEnvironment& env, char const* url,
00739 NetAddress& address,
00740 portNumBits& portNum) {
00741 do {
00742
00743
00744
00745 char const* prefix = "sip:";
00746 unsigned const prefixLength = 4;
00747 if (_strncasecmp(url, prefix, prefixLength) != 0) {
00748 env.setResultMsg("URL is not of the form \"", prefix, "\"");
00749 break;
00750 }
00751
00752 unsigned const parseBufferSize = 100;
00753 char parseBuffer[parseBufferSize];
00754 unsigned addressStartIndex = prefixLength;
00755 while (url[addressStartIndex] != '\0'
00756 && url[addressStartIndex++] != '@') {}
00757 char const* from = &url[addressStartIndex];
00758
00759
00760 char const* from1 = from;
00761 while (*from1 != '\0' && *from1 != '/') {
00762 if (*from1 == '@') {
00763 from = ++from1;
00764 break;
00765 }
00766 ++from1;
00767 }
00768
00769 char* to = &parseBuffer[0];
00770 unsigned i;
00771 for (i = 0; i < parseBufferSize; ++i) {
00772 if (*from == '\0' || *from == ':' || *from == '/') {
00773
00774 *to = '\0';
00775 break;
00776 }
00777 *to++ = *from++;
00778 }
00779 if (i == parseBufferSize) {
00780 env.setResultMsg("URL is too long");
00781 break;
00782 }
00783
00784 NetAddressList addresses(parseBuffer);
00785 if (addresses.numAddresses() == 0) {
00786 env.setResultMsg("Failed to find network address for \"",
00787 parseBuffer, "\"");
00788 break;
00789 }
00790 address = *(addresses.firstAddress());
00791
00792 portNum = 5060;
00793 char nextChar = *from;
00794 if (nextChar == ':') {
00795 int portNumInt;
00796 if (sscanf(++from, "%d", &portNumInt) != 1) {
00797 env.setResultMsg("No port number follows ':'");
00798 break;
00799 }
00800 if (portNumInt < 1 || portNumInt > 65535) {
00801 env.setResultMsg("Bad port number");
00802 break;
00803 }
00804 portNum = (portNumBits)portNumInt;
00805 }
00806
00807 return True;
00808 } while (0);
00809
00810 return False;
00811 }
00812
00813 Boolean SIPClient::parseSIPURLUsernamePassword(char const* url,
00814 char*& username,
00815 char*& password) {
00816 username = password = NULL;
00817 do {
00818
00819 char const* prefix = "sip:";
00820 unsigned const prefixLength = 4;
00821 if (_strncasecmp(url, prefix, prefixLength) != 0) break;
00822
00823
00824 unsigned usernameIndex = prefixLength;
00825 unsigned colonIndex = 0, atIndex = 0;
00826 for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) {
00827 if (url[i] == ':' && colonIndex == 0) {
00828 colonIndex = i;
00829 } else if (url[i] == '@') {
00830 atIndex = i;
00831 break;
00832 }
00833 }
00834 if (atIndex == 0) break;
00835
00836 char* urlCopy = strDup(url);
00837 urlCopy[atIndex] = '\0';
00838 if (colonIndex > 0) {
00839 urlCopy[colonIndex] = '\0';
00840 password = strDup(&urlCopy[colonIndex+1]);
00841 } else {
00842 password = strDup("");
00843 }
00844 username = strDup(&urlCopy[usernameIndex]);
00845 delete[] urlCopy;
00846
00847 return True;
00848 } while (0);
00849
00850 return False;
00851 }
00852
00853 char*
00854 SIPClient::createAuthenticatorString(Authenticator const* authenticator,
00855 char const* cmd, char const* url) {
00856 if (authenticator != NULL && authenticator->realm() != NULL
00857 && authenticator->nonce() != NULL && authenticator->username() != NULL
00858 && authenticator->password() != NULL) {
00859
00860 char* const authFmt = "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", response=\"%s\", uri=\"%s\"\r\n";
00861 char const* response = authenticator->computeDigestResponse(cmd, url);
00862 unsigned authBufSize = strlen(authFmt)
00863 + strlen(authenticator->username()) + strlen(authenticator->realm())
00864 + strlen(authenticator->nonce()) + strlen(url) + strlen(response);
00865 char* authenticatorStr = new char[authBufSize];
00866 sprintf(authenticatorStr, authFmt,
00867 authenticator->username(), authenticator->realm(),
00868 authenticator->nonce(), response, url);
00869 authenticator->reclaimDigestResponse(response);
00870
00871 return authenticatorStr;
00872 }
00873
00874 return strDup("");
00875 }
00876
00877 Boolean SIPClient::sendRequest(char const* requestString,
00878 unsigned requestLength) {
00879 if (fVerbosityLevel >= 1) {
00880 envir() << "Sending request: " << requestString << "\n";
00881 }
00882
00883
00884 return fOurSocket->output(envir(), 255, (unsigned char*)requestString,
00885 requestLength);
00886 }
00887
00888 unsigned SIPClient::getResponse(char*& responseBuffer,
00889 unsigned responseBufferSize) {
00890 if (responseBufferSize == 0) return 0;
00891 responseBuffer[0] = '\0';
00892
00893
00894
00895
00896 char* p = responseBuffer;
00897 Boolean haveSeenNonCRLF = False;
00898 int bytesRead = 0;
00899 while (bytesRead < (int)responseBufferSize) {
00900 unsigned bytesReadNow;
00901 struct sockaddr_in fromAddr;
00902 unsigned char* toPosn = (unsigned char*)(responseBuffer+bytesRead);
00903 Boolean readSuccess
00904 = fOurSocket->handleRead(toPosn, responseBufferSize-bytesRead,
00905 bytesReadNow, fromAddr);
00906 if (!readSuccess || bytesReadNow == 0) {
00907 envir().setResultMsg("SIP response was truncated");
00908 break;
00909 }
00910 bytesRead += bytesReadNow;
00911
00912
00913 char* lastToCheck = responseBuffer+bytesRead-4;
00914 if (lastToCheck < responseBuffer) continue;
00915 for (; p <= lastToCheck; ++p) {
00916 if (haveSeenNonCRLF) {
00917 if (*p == '\r' && *(p+1) == '\n' &&
00918 *(p+2) == '\r' && *(p+3) == '\n') {
00919 responseBuffer[bytesRead] = '\0';
00920
00921
00922 while (*responseBuffer == '\r' || *responseBuffer == '\n') {
00923 ++responseBuffer;
00924 --bytesRead;
00925 }
00926 return bytesRead;
00927 }
00928 } else {
00929 if (*p != '\r' && *p != '\n') {
00930 haveSeenNonCRLF = True;
00931 }
00932 }
00933 }
00934 }
00935
00936 return 0;
00937 }
00938
00939 Boolean SIPClient::parseResponseCode(char const* line,
00940 unsigned& responseCode) {
00941 if (sscanf(line, "%*s%u", &responseCode) != 1) {
00942 envir().setResultMsg("no response code in line: \"", line, "\"");
00943 return False;
00944 }
00945
00946 return