JAIN SIP #8 (Create Invite ตอนที่ 2 )

JAIN SIP #8 (Create Invite ตอนที่ 2 )

มาต่อเรื่อง Create Invite กันนะครับ ความเดิมตอนที่แล้ว ผมอธิบายวิธีการสร้าง SIP Invite message แบบรวดย่อ (มาก ๆ) โดยการใช้พวก Header Factory ทั้งหลายสร้าง SIP Invite header มา แล้วก็จับยัดใน Request object แล้วก็ให้ Client Transaction Object ส่งไปหาผู้รับ

แต่ทว่าเรื่องราวมันก็ยังไม่จบเพียงแค่นั้น เพราะว่า เมื่อผู้รับได้ัรับ Invite Request ของเราแล้ว เค้าก็จะทำการพิสูจน์ตัวตนก่อนว่าเป็นเราจริงหรือไม่ โดยการส่ง Proxy Authentication ตาม Flow เำก่า ดังนี้

ผู้ส่ง                                  ผู้รับ

           Invite + SDP -------> 
  <--- Proxy Authentication
  <--- Trying
  <--- Ringing

  Invite + SDP + Authen -->
  <--- 200 OK + SDP

จากนั้นผู้รับก็จะส่ง Proxy Authentication , Trying, Ringing มาเป็นชุด ๆ ทีนี้ก็เป็นหน้าที่เรา ที่จะต้องส่ง Invite + SDP และ Authentication แนบท้าย SIP Invite Message ด้วย เวลาที่ผู้รับ ส่ง message ตอบกลับมา มันก็จะไปเรียกฟังก์ชัน processResponse โดยอัตโนมัติ ดังนี้

public void processResponse(ResponseEvent responseReceivedEvent) {

        System.out.println("Got a response");
        Response response = (Response) responseReceivedEvent.getResponse();
        ClientTransaction tid = responseReceivedEvent.getClientTransaction();
        CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);

        System.out.println("Response received : Status Code = "
                + response.getStatusCode() + " [" +response.getReasonPhrase() + "] "+ cseq);
        if (tid == null) {
            System.out.println("Stray response -- dropping ");
            return;
        }

        try {

         if (response.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED    )
            {
                System.out.println(" ENTER Proxy Authentication");
                URI uriReq = tid.getRequest().getRequestURI();
                Request authrequest = this.processResponseAuthorization(response, uriReq);
                inviteTid = sipProvider.getNewClientTransaction(authrequest);
                inviteTid.sendRequest();
                System.out.println("INVITE AUTHORIZATION sent:\n");               
            }
            System.out.println("Finish response process");
         } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("From process Response");
            System.exit(0);
        }

    }

เราสามารถตรวจสอบ Proxy Authentication ผ่าน status code จากนั้นก็เข้าไปสร้าง Invite message ใหม่ โดยเรียกฟังก์ชัน processResponseAuthorization();

    public Request processResponseAuthorization(Response response, URI uriReq) {
        Request requestauth = null;


        try {
            ProxyAuthenticate ss = (ProxyAuthenticate)response.getHeader(SIPHeaderNames.PROXY_AUTHENTICATE);
                    
            String schema = ((ProxyAuthenticate) (response
                    .getHeader(SIPHeaderNames.PROXY_AUTHENTICATE))).getScheme();         

            String nonce = ((ProxyAuthenticate) (response
                    .getHeader(SIPHeaderNames.PROXY_AUTHENTICATE))).getNonce();

            ProxyAuthorizationHeader proxyAuthheader = headerFactory
                    .createProxyAuthorizationHeader(schema);
            proxyAuthheader.setUsername(USER_AUTH);
            proxyAuthheader.setRealm(realm);
            proxyAuthheader.setNonce(nonce);
            proxyAuthheader.setURI(uriReq);

            DigestClientAuthenticationMethod digest = new DigestClientAuthenticationMethod();

            String callId = ((CallIdHeader) response
                    .getHeader(CallIdHeader.NAME)).getCallId();
            requestauth = this.createInvite(callId);

            digest.initialize(realm, USER_AUTH, uriReq.toString(), nonce,
                    PASS_AUTH, ((CSeqHeader) response
                            .getHeader(CSeqHeader.NAME)).getMethod(), null,
                    "MD5");
            //System.out.println("Proxy Response antes de modificarlo : "
            //        + proxyAuthheader.getResponse());
            String respuestaM = digest.generateResponse();
            proxyAuthheader.setResponse(respuestaM);
            proxyAuthheader.setAlgorithm("MD5");

            requestauth.addHeader(proxyAuthheader);

        }

        catch (ParseException pa) {
            System.out.println("processResponseAuthorization() ParseException: 1");
            System.out.println(pa.getMessage());
            pa.printStackTrace();
        }

         catch (Exception ex) {
            System.out.println("processResponseAuthorization() Exception: 2");
            System.out.println(ex.getMessage());
            ex.printStackTrace();
        }
        return requestauth;

    }

ฟังก์ชันนี้มีการทำงานแทบจะเหมือนกับตอนที่เรา Register ไปยัง SIP Server แล้ว ได้รับ Unauthorize มา เพราะเราก็สร้าง message digest โดยใช้ MD5 algorithm  จุดที่น่าสนใจของฟังก์ชันนี้จะเห็นได้ว่ามีการเรียก createInvite อีกครั้งโดยการส่ง call ID ไปให้ด้วย เพื่ออ้างอิง SIP Session เดิม แล้วก็ไปสร้าง SIP Invite message ใหม่ จากนั้นก็เอา authentication แนบท้ายใน request เพื่อเตรียมส่งการร้องขอไปอีกครั้ง

วิธีการส่งการร้องขอ ก็ใช้รูปแบบเดิม คือ หลังจากที่สร้าง Invite Request เสร็จเรียบร้อย เราก็เอา client Transaction (inviteTid) ในการส่ง โดยเรียก inviteTid.sendRequest();