/** * Creates a SIP response message. * * @param req the request message * @param code the response code * @param reason the response reason * @param contact the contact address * @param local_tag the local tag in the 'To' header * @param body the message body */ public static Message createResponse( Message req, int code, String reason, String local_tag, NameAddress contact, String content_type, String body) { Message resp = new Message(); resp.setStatusLine(new StatusLine(code, reason)); resp.setVias(req.getVias()); if (code >= 180 && code < 300 && req.hasRecordRouteHeader()) resp.setRecordRoutes(req.getRecordRoutes()); ToHeader toh = req.getToHeader(); if (local_tag != null) toh.setParameter("tag", local_tag); resp.setToHeader(toh); resp.setFromHeader(req.getFromHeader()); resp.setCallIdHeader(req.getCallIdHeader()); resp.setCSeqHeader(req.getCSeqHeader()); if (contact != null) resp.setContactHeader(new ContactHeader(contact)); // add Server header field if (SipStack.server_info != null) resp.setServerHeader(new ServerHeader(SipStack.server_info)); // if (body!=null) resp.setBody(body); else resp.setBody(""); if (content_type == null) resp.setBody(body); else resp.setBody(content_type, body); // System.out.println("DEBUG: MessageFactory: // response:\n"+resp.toString()); return resp; }
/** Creates a CANCEL request. */ public static Message createCancelRequest(Message method, Dialog dialog) { ToHeader to = method.getToHeader(); FromHeader from = method.getFromHeader(); SipURL request_uri = method.getRequestLine().getAddress(); NameAddress contact = method.getContactHeader().getNameAddress(); ViaHeader via = method.getViaHeader(); String host_addr = via.getHost(); int host_port = via.getPort(); boolean rport = via.hasRport(); String proto = via.getProtocol(); String branch = method.getViaHeader().getBranch(); return createRequest( SipMethods.CANCEL, request_uri, to.getNameAddress(), from.getNameAddress(), contact, proto, host_addr, host_port, rport, method.getCallIdHeader().getCallId(), method.getCSeqHeader().getSequenceNumber(), from.getParameter("tag"), to.getParameter("tag"), branch, "", null, null); // modified by mandrajg }
/** * Responds with <i>resp</i>. This method can be called when the InviteDialog is in D_INVITED or * D_BYED states. * * <p>If the CSeq method is INVITE and the response is 2xx, it moves to state D_ACCEPTED, adds a * new listener to the SipProviderListener, and creates new AckTransactionServer * * <p>If the CSeq method is INVITE and the response is not 2xx, it moves to state D_REFUSED, and * sends the response. */ public void respond(Message resp) // private void respond(Message resp) { printLog("inside respond(resp)", LogLevel.MEDIUM); String method = resp.getCSeqHeader().getMethod(); if (method.equals(SipMethods.INVITE)) { if (!verifyStatus(statusIs(D_INVITED) || statusIs(D_ReINVITED))) { printLog( "respond(): InviteDialog not in (re)invited state: No response now", LogLevel.HIGH); return; } int code = resp.getStatusLine().getCode(); // 1xx provisional responses if (code >= 100 && code < 200) { invite_ts.respondWith(resp); return; } // For all final responses establish the dialog if (code >= 200) { // changeStatus(D_ACCEPTED); update(Dialog.UAS, resp); } // 2xx success responses if (code >= 200 && code < 300) { if (statusIs(D_INVITED)) changeStatus(D_ACCEPTED); else changeStatus(D_ReACCEPTED); // terminates the INVITE Transaction server and activates an ACK // Transaction server invite_ts.terminate(); ConnectionIdentifier conn_id = invite_ts.getConnectionId(); ack_ts = new AckTransactionServer(sip_provider, conn_id, resp, this); ack_ts.respond(); // if (statusIs(D_ReACCEPTED)) // listener.onDlgReInviteAccepted(this); // else listener.onDlgAccepted(this); return; } else // 300-699 failure responses // if (code>=300) { if (statusIs(D_INVITED)) changeStatus(D_REFUSED); else changeStatus(D_ReREFUSED); invite_ts.respondWith(resp); // if (statusIs(D_ReREFUSED)) // listener.onDlgReInviteRefused(this); // else listener.onDlgRefused(this); return; } } if (method.equals(SipMethods.BYE)) { if (!verifyStatus(statusIs(D_BYED))) return; bye_ts.respondWith(resp); } }
/** Creates an ACK request for a non-2xx response */ public static Message createNon2xxAckRequest( SipProvider sip_provider, Message method, Message resp) { SipURL request_uri = method.getRequestLine().getAddress(); FromHeader from = method.getFromHeader(); ToHeader to = resp.getToHeader(); String via_addr = sip_provider.getViaAddress(); int host_port = sip_provider.getPort(); boolean rport = sip_provider.isRportSet(); String proto; if (request_uri.hasTransport()) proto = request_uri.getTransport(); else proto = sip_provider.getDefaultTransport(); String branch = method.getViaHeader().getBranch(); NameAddress contact = null; Message ack = createRequest( SipMethods.ACK, request_uri, to.getNameAddress(), from.getNameAddress(), contact, proto, via_addr, host_port, rport, method.getCallIdHeader().getCallId(), method.getCSeqHeader().getSequenceNumber(), from.getParameter("tag"), to.getParameter("tag"), branch, null, null, null); // modified by mandrajg ack.removeExpiresHeader(); if (method.hasRouteHeader()) ack.setRoutes(method.getRoutes()); return ack; }
/** * Inherited from class SipProviderListener. Called when a new message is received (out of any * ongoing transaction) for the current InviteDialog. Always checks for out-of-date methods (CSeq * header sequence number). * * <p>If the message is ACK(2xx/INVITE) request, it moves to D_CALL state, and fires * <i>onDlgAck(this,body,msg)</i>. * * <p>If the message is 2xx(INVITE) response, it create a new AckTransactionClient * * <p>If the message is BYE, it moves to D_BYED state, removes the listener from SipProvider, * fires onDlgBye(this,msg) then it responds with 200 OK, moves to D_CLOSE state and fires * onDlgClose(this) */ public void onReceivedMessage(SipProvider sip_provider, Message msg) { printLog("inside onReceivedMessage(sip_provider,message)", LogLevel.MEDIUM); if (msg.isRequest() && !(msg.isAck() || msg.isCancel()) && msg.getCSeqHeader().getSequenceNumber() <= getRemoteCSeq()) { printLog("Request message is too late (CSeq too small): Message discarded", LogLevel.HIGH); return; } // invite received if (msg.isRequest() && msg.isInvite()) { verifyStatus(statusIs(D_INIT) || statusIs(D_CALL)); // NOTE: if the invite_ts.listen() is used, you should not arrive // here with the D_INIT state.. // however state D_INIT has been included for robustness against // further changes. if (statusIs(D_INIT)) changeStatus(D_INVITED); else changeStatus(D_ReINVITED); invite_req = msg; invite_ts = new InviteTransactionServer(sip_provider, invite_req, this); // ((TransactionServer)transaction).listen(); update(Dialog.UAS, invite_req); if (statusIs(D_INVITED)) listener.onDlgInvite( this, invite_req.getToHeader().getNameAddress(), invite_req.getFromHeader().getNameAddress(), invite_req.getBody(), invite_req); else listener.onDlgReInvite(this, invite_req.getBody(), invite_req); } else // ack (of 2xx of INVITE) if (msg.isRequest() && msg.isAck()) { if (!verifyStatus(statusIs(D_ACCEPTED) || statusIs(D_ReACCEPTED))) return; changeStatus(D_CALL); // terminates the AckTransactionServer ack_ts.terminate(); listener.onDlgAck(this, msg.getBody(), msg); listener.onDlgCall(this); } else // keep sending ACK (if already sent) for any "200 OK" received if (msg.isResponse()) { if (!verifyStatus(statusIs(D_CALL))) return; int code = msg.getStatusLine().getCode(); verifyThat(code >= 200 && code < 300, "code 2xx was expected"); if (ack_req != null) { AckTransactionClient ack_tc = new AckTransactionClient(sip_provider, ack_req, null); ack_tc.request(); } } else // bye received if (msg.isRequest() && msg.isBye()) { if (!verifyStatus(statusIs(D_CALL) || statusIs(D_BYEING))) return; changeStatus(D_BYED); bye_ts = new TransactionServer(sip_provider, msg, this); // automatically sends a 200 OK Message resp = MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null); respond(resp); listener.onDlgBye(this, msg); changeStatus(D_CLOSE); listener.onDlgClose(this); } else // cancel received if (msg.isRequest() && msg.isCancel()) { if (!verifyStatus(statusIs(D_INVITED) || statusIs(D_ReINVITED))) return; // create a CANCEL TransactionServer and send a 200 OK (CANCEL) TransactionServer ts = new TransactionServer(sip_provider, msg, null); // ts.listen(); ts.respondWith(MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null)); // automatically sends a 487 Cancelled Message resp = MessageFactory.createResponse(invite_req, 487, SipResponses.reasonOf(487), null); respond(resp); listener.onDlgCancel(this, msg); } else // any other request received if (msg.isRequest()) { TransactionServer ts = new TransactionServer(sip_provider, msg, null); // ts.listen(); ts.respondWith(MessageFactory.createResponse(msg, 405, SipResponses.reasonOf(405), null)); } }
/** When the TransactionClient goes into the "Completed" state receiving a 300-699 response */ public void onTransFailureResponse(TransactionClient tc, Message msg) { // SESCA // Autentikointi String method = tc.getTransactionMethod(); StatusLine status_line = msg.getStatusLine(); int code = status_line.getCode(); // AUTHENTICATION-BEGIN if ((code == 401 && msg.hasWwwAuthenticateHeader() && msg.getWwwAuthenticateHeader().getRealmParam().equalsIgnoreCase(user_profile.realm)) || (code == 407 && msg.hasProxyAuthenticateHeader() && msg.getProxyAuthenticateHeader() .getRealmParam() .equalsIgnoreCase(user_profile.realm))) { // req:ssa on cseq:ua kasvatettu Message req = tc.getRequestMessage(); req.setCSeqHeader(req.getCSeqHeader().incSequenceNumber()); WwwAuthenticateHeader wah; if (code == 401) wah = msg.getWwwAuthenticateHeader(); else wah = msg.getProxyAuthenticateHeader(); String qop_options = wah.getQopOptionsParam(); qop = (qop_options != null) ? "auth" : null; RequestLine rl = req.getRequestLine(); // SESCA // BUGI client ei saa lähettää qop:ia // DigestAuthentication digest=new // DigestAuthentication(rl.getMethod(),rl.getAddress().toString(),wah,qop,null,username,passwd); DigestAuthentication digest = new DigestAuthentication( rl.getMethod(), rl.getAddress().toString(), wah, null, null, user_profile.authID, user_profile.passwd); AuthorizationHeader ah; if (code == 401) ah = digest.getAuthorizationHeader(); else ah = digest.getProxyAuthorizationHeader(); req.setAuthorizationHeader(ah); // transactions.remove(tc.getTransactionId()); // SESCA // BUGI // Päivitetään invite_req:uun uusin invite-viesti. // Lähetämme uuden inviten, joten teemme uuden invitetransactionclientin, eikä transaction // clientia // if (method.equals(SipMethods.INVITE)) { // invite_req = req; // tc=new InviteTransactionClient(sip_provider,req,this); tc = new TransactionClient(sip_provider, req, this); // tc=new TransactionClient(sip_provider,req,this); // } // else { // tc=new TransactionClient(sip_provider,req,this); // } // transactions.put(tc.getTransactionId(),tc); tc.request(); } // AUTHENTICATION-END else onDeliveryFailure(tc, msg.getStatusLine().getReason()); }