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), 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);
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
00075
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
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
00095 char const* formatStr;
00096 unsigned headerSize;
00097
00098
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 }
00119
00120 SIPClient::~SIPClient() {
00121 reset();
00122
00123 delete[] fUserAgentHeaderStr;
00124 delete fOurSocket;
00125 delete[] (char*)fOurAddressStr;
00126 delete[] (char*)fApplicationName;
00127 delete[] (char*)fMIMESubtype;
00128 }
00129
00130 void SIPClient::reset() {
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 }
00145
00146 void SIPClient::setProxyServer(unsigned proxyServerAddress,
00147 portNumBits proxyServerPortNum) {
00148 fServerAddress.s_addr = proxyServerAddress;
00149 fServerPortNum = proxyServerPortNum;
00150 if (fOurSocket != NULL) {
00151 fOurSocket->changeDestinationParameters(fServerAddress,
00152 fServerPortNum, 255);
00153 }
00154 }
00155
00156 static char* getLine(char* startOfLine) {
00157
00158 for (char* ptr = startOfLine; *ptr != '\0'; ++ptr) {
00159 if (*ptr == '\r' || *ptr == '\n') {
00160
00161 *ptr++ = '\0';
00162 if (*ptr == '\n') ++ptr;
00163 return ptr;
00164 }
00165 }
00166
00167 return NULL;
00168 }
00169
00170 char* SIPClient::invite(char const* url, Authenticator* authenticator) {
00171
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_random32();
00186 fFromTag = our_random32();
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* 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* 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* 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"
00254 "%s"
00255 "Content-Length: %d\r\n\r\n"
00256 "%s";
00257 unsigned inviteCmdSize = strlen(cmdFmt)
00258 + fURLSize
00259 + 2*fUserNameSize + fOurAddressStrSize + 20
00260 + fOurAddressStrSize + 5
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
00286
00287 fInviteClientState = Calling;
00288 fEventLoopStopFlag = 0;
00289 TaskScheduler& sched = envir().taskScheduler();
00290 sched.turnOnBackgroundReadHandling(fOurSocket->socketNum(),
00291 &inviteResponseHandler, this);
00292 fTimerALen = 1*fT1;
00293 fTimerACount = 0;
00294 fTimerA = sched.scheduleDelayedTask(fTimerALen, timerAHandler, this);
00295 fTimerB = sched.scheduleDelayedTask(64*fT1, timerBHandler, this);
00296 fTimerD = NULL;
00297
00298 if (!sendINVITE()) break;
00299
00300
00301 envir().taskScheduler().doEventLoop(&fEventLoopStopFlag);
00302
00303
00304
00305 sched.turnOffBackgroundReadHandling(fOurSocket->socketNum());
00306 sched.unscheduleDelayedTask(fTimerA);
00307 sched.unscheduleDelayedTask(fTimerB);
00308 sched.unscheduleDelayedTask(fTimerD);
00309
00310
00311
00312
00313 if (fInviteSDPDescription != NULL) {
00314 return strDup(fInviteSDPDescription);
00315 }
00316 } while (0);
00317
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 delete[] fInviteSDPDescriptionReturned; fInviteSDPDescriptionReturned = NULL;
00438 }
00439
00440
00441 fEventLoopStopFlag = ~0;
00442 }
00443
00444 Boolean SIPClient::sendINVITE() {
00445 if (!sendRequest(fInviteCmd, fInviteCmdSize)) {
00446 envir().setResultErrMsg("INVITE send() failed: ");
00447 return False;
00448 }
00449 return True;
00450 }
00451
00452 unsigned SIPClient::getResponseCode() {
00453 unsigned responseCode = 0;
00454 do {
00455
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
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
00476
00477
00478
00479
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;
00487
00488 char* realm = strDupSize(lineStart);
00489 char* nonce = strDupSize(lineStart);
00490
00491
00492
00493 Boolean foundAuthenticateHeader = False;
00494 if (
00495
00496 sscanf(lineStart, "Proxy-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"",
00497 realm, nonce) == 2 ||
00498
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
00513
00514
00515
00516
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;
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
00544 if (lineStart == NULL) {
00545 envir().setResultMsg("no content following header lines: ", readBuf);
00546 break;
00547 }
00548
00549
00550
00551
00552 char* bodyStart = nextLineStart;
00553 if (bodyStart != NULL && contentLength >= 0) {
00554
00555 unsigned numBodyBytes = &readBuf[bytesRead] - bodyStart;
00556 if (contentLength > (int)numBodyBytes) {
00557
00558
00559 unsigned numExtraBytesNeeded = contentLength - numBodyBytes;
00560 #ifdef USING_TCP
00561
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
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;
00598 }
00599
00600 bodyStart[contentLength] = '\0';
00601 delete[] fInviteSDPDescriptionReturned; fInviteSDPDescriptionReturned = strDup(bodyStart);
00602 }
00603 } while (0);
00604
00605 return responseCode;
00606 }
00607
00608 char* SIPClient::inviteWithPassword(char const* url, char const* username,
00609 char const* password) {
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
00617 return inviteResult;
00618 }
00619
00620
00621 if (authenticator.realm() == NULL || authenticator.nonce() == NULL) {
00622
00623 return NULL;
00624 }
00625
00626
00627 inviteResult = invite1(&authenticator);
00628 if (inviteResult != NULL) {
00629
00630 fValidAuthenticator = authenticator;
00631 }
00632
00633 return inviteResult;
00634 }
00635
00636 Boolean SIPClient::sendACK() {
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
00651 + fOurAddressStrSize + 5
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 );
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 }
00676
00677 Boolean SIPClient::sendBYE() {
00678
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
00693 + fOurAddressStrSize + 5
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 }
00718
00719 Boolean SIPClient::processURL(char const* url) {
00720 do {
00721
00722
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 }
00739
00740 Boolean SIPClient::parseSIPURL(UsageEnvironment& env, char const* url,
00741 NetAddress& address,
00742 portNumBits& portNum) {
00743 do {
00744
00745
00746
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
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
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;
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 }
00814
00815 Boolean SIPClient::parseSIPURLUsernamePassword(char const* url,
00816 char*& username,
00817 char*& password) {
00818 username = password = NULL;
00819 do {
00820
00821 char const* prefix = "sip:";
00822 unsigned const prefixLength = 4;
00823 if (_strncasecmp(url, prefix, prefixLength) != 0) break;
00824
00825
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;
00834 }
00835 }
00836 if (atIndex == 0) break;
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 }
00854
00855 char*
00856 SIPClient::createAuthenticatorString(Authenticator const* authenticator,
00857 char const* cmd, char const* url) {
00858 if (authenticator != NULL && authenticator->realm() != NULL
00859 && authenticator->nonce() != NULL && authenticator->username() != NULL
00860 && authenticator->password() != NULL) {
00861
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 }
00879
00880 Boolean SIPClient::sendRequest(char const* requestString,
00881 unsigned requestLength) {
00882 if (fVerbosityLevel >= 1) {
00883 envir() << "Sending request: " << requestString << "\n";
00884 }
00885
00886
00887 return fOurSocket->output(envir(), 255, (unsigned char*)requestString,
00888 requestLength);
00889 }
00890
00891 unsigned SIPClient::getResponse(char*& responseBuffer,
00892 unsigned responseBufferSize) {
00893 if (responseBufferSize == 0) return 0;
00894 responseBuffer[0] = '\0';
00895
00896
00897
00898
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
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
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 }
00941
00942 Boolean SIPClient::parseResponseCode(char const* line,
00943 unsigned& responseCode) {
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 }