*/
public void sendRequest() throws SipException {
SIPRequest sipRequest = this.getOriginalRequest();
if (this.getInternalState() >= 0)
throw new SipException("Request already sent");
if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
sipStack.getStackLogger().logDebug("sendRequest() " + sipRequest);
}
try {
sipRequest.checkHeaders();
} catch (ParseException ex) {
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logError("missing required header");
throw new SipException(ex.getMessage());
}
if (getMethod().equals(Request.SUBSCRIBE)
&& sipRequest.getHeader(ExpiresHeader.NAME) == null) {
/*
* If no "Expires" header is present in a SUBSCRIBE request, the implied default is
* defined by the event package being used.
*
*/
if (sipStack.isLoggingEnabled())
sipStack.getStackLogger().logWarning(
"Expires header missing in outgoing subscribe --"
+ " Notifier will assume implied value on event package");
}
try {
/*
* This check is removed because it causes problems for load balancers ( See issue
* 136) reported by Raghav Ramesh ( BT )
*
*/
if (this.getMethod().equals(Request.CANCEL)
&& sipStack.isCancelClientTransactionChecked()) {
SIPClientTransaction ct = (SIPClientTransaction) sipStack.findCancelTransaction(
this.getOriginalRequest(), false);
if (ct == null) {
/*
* If the original request has generated a final response, the CANCEL SHOULD
* NOT be sent, as it is an effective no-op, since CANCEL has no effect on
* requests that have already generated a final response.
*/
throw new SipException("Could not find original tx to cancel. RFC 3261 9.1");
} else if (ct.getInternalState() < 0) {
throw new SipException(
"State is null no provisional response yet -- cannot cancel RFC 3261 9.1");
} else if (!ct.isInviteTransaction()) {
throw new SipException("Cannot cancel non-invite requests RFC 3261 9.1");
}
} else if (this.getMethod().equals(Request.BYE)
|| this.getMethod().equals(Request.NOTIFY)) {
SIPDialog dialog = sipStack.getDialog(this.getOriginalRequest()
.getDialogId(false));
// I want to behave like a user agent so send the BYE using the
// Dialog
if (this.getSipProvider().isAutomaticDialogSupportEnabled() && dialog != null) {
throw new SipException(
"Dialog is present and AutomaticDialogSupport is enabled for "
+ " the provider -- Send the Request using the Dialog.sendRequest(transaction)");
}
}
// Only map this after the fist request is sent out.
if (isInviteTransaction()) {
SIPDialog dialog = this.getDefaultDialog();
if (dialog != null && dialog.isBackToBackUserAgent()) {
// Block sending re-INVITE till we see the ACK.
if ( ! dialog.takeAckSem() ) {
throw new SipException ("Failed to take ACK semaphore");
}
}
}
this.isMapped = true;
// Time extracted from the Expires header.
int expiresTime = -1;
if ( sipRequest.getHeader(ExpiresHeader.NAME) != null ) {
Expires expires = (Expires) sipRequest.getHeader(ExpiresHeader.NAME);
expiresTime = expires.getExpires();
}
// This is a User Agent. The user has specified an Expires time. Start a timer
// which will check if the tx is terminated by that time.
if ( this.getDefaultDialog() != null && isInviteTransaction() &&
expiresTime != -1 && expiresTimerTask == null ) {
this.expiresTimerTask = new ExpiresTimerTask();
sipStack.getTimer().schedule(expiresTimerTask, expiresTime * 1000);
}
this.sendMessage(sipRequest);
} catch (IOException ex) {
this.setState(TransactionState._TERMINATED);
if ( this.expiresTimerTask != null ) {
sipStack.getTimer().cancel(this.expiresTimerTask);
}
throw new SipException(
ex.getMessage() == null ? "IO Error sending request" : ex.getMessage(),
ex);
}
}