SIP servlets, chatserver

2019-06-03 15:44发布

I'm trying to get a SIP servlet chat server working, together with the textclient found here.

When I use 2 clients to send messages to eachother (peer to peer), everything goes well. But when I use one or more clients together with my server, I have to wait exactly 32 seconds before the server picks up any new messages in the doMessage() method. I'm using Netbeans together with Sailfin as my SIP server. Is there some kind of limitation or configurable delay or timeout between requests or responses in Sailfin I'm looking over?

I can post the server code, if needed.

Thanks

3条回答
The star\"
2楼-- · 2019-06-03 15:59

Here is the code of the server, i'll try to make a wireshark trace later.

public class ChatroomSipServlet extends SipServlet {

    public final static String USER_LIST = "userList";

    public final static String CHATROOM_SERVER_NAME = "chatroomservername";

    public String serverAddress;
    public SipFactory factory;

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
        System.out.println("Chatroom sip servlet is gestart!");
        try {
            factory = (SipFactory) getServletContext().getAttribute("javax.servlet.sip.SipFactory");
            System.out.println("Sip Factory: " + factory);
        } catch (Exception e) {
            throw new ServletException("Factory probleem!", e);
        }
        getServletContext().setAttribute(USER_LIST, new ArrayList<String>());
        serverAddress = getServletConfig().getInitParameter(CHATROOM_SERVER_NAME);
        System.out.println("serverAddress is: " + serverAddress);
    }

    @Override
    public void destroy() {
        try {
            sendToAll(serverAddress, "Server sluit af!");
        } catch (Throwable e) {

            e.printStackTrace();
        }
        super.destroy();
    }

    protected void doMessage(SipServletRequest request) throws ServletException, IOException {

        System.out.println(getDateTime() + " Bericht ontvangen");

        request.createResponse(SipServletResponse.SC_OK).send();

        String message = request.getContent().toString();
        String from = ((SipURI) request.getFrom().getURI()).toString();

        if (message.equalsIgnoreCase("/quit")) {
            sendToUser(from, "Bye");
            removeUser(from);
            return;
        }

        if (!containsUser(from)) {
            sendToUser(from, "Welkom in de chatroom. Typ '/quit' om af te sluiten.");
            addUser(from);
        }

        if (message.equalsIgnoreCase("/who")) {
            String users = "Lijst van de gebruikers:\n";
            List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
            for (String user : list) {
                users += user + "\n";
            }
            sendToUser(from, users);
            return;
        }

        if (message.equalsIgnoreCase("/join")) {
            return;
        }

        sendToAll(from, message);
    }

    protected void doErrorResponse(SipServletResponse response) throws ServletException, IOException {

//      String receiver = response.getTo().toString();
        String receiver = ((SipURI) response.getTo().getURI()).toString();
        System.out.println(getDateTime() + " Errorresponse voor " + receiver);
        removeUser(receiver);
    }

    protected void doSuccessResponse(SipServletResponse response) throws ServletException, IOException {

        response.getApplicationSession().invalidate();
    }

    private void sendToAll(String from, String message) throws ServletParseException, IOException {

        List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
        for (String user : list) {
            SipApplicationSession session = factory.createApplicationSession();
            System.out.println(getDateTime() + " Session created voor " + user);
            SipServletRequest request = factory.createRequest(session, "MESSAGE", serverAddress, user);
            String msg = from + " stuurt: \n" + message;
            request.setContent(msg.getBytes(), "text/plain");
            request.send();
        }
    }

    private void sendToUser(String to, String message) throws ServletParseException, IOException {

        SipApplicationSession session = factory.createApplicationSession();
        SipServletRequest request = factory.createRequest(session, "MESSAGE", serverAddress, to);
        request.setContent(message.getBytes(), "text/plain");
        request.send();
    }

    private boolean containsUser(String from) {
        List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
        return list.contains(from);
    }

    private void addUser(String from) {
        List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
        list.add(from);
    }

    private void removeUser(String from) {
        System.out.println(getDateTime() + " " + from + " wordt verwijderd uit de lijst.");
        List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
        list.remove(from);

    }

    @Override
    protected void doRegister(SipServletRequest req) throws ServletException, IOException {
        System.out.println("Register request ontvangen: " + req.getTo());
        int response = SipServletResponse.SC_OK;
        SipServletResponse resp = req.createResponse(response);
        resp.send();
    }

    private String getDateTime() {
        DateFormat dateFormat = new SimpleDateFormat("[" + "HH:mm:ss" + "]");
        Date date = new Date();
        return dateFormat.format(date);
    }
}

And the sip.xml

<sip-app>
    <app-name>sip.chatvoorbeeld.ChatServer</app-name>
    <display-name>Chatroom Sip Servlet</display-name>
    <description>Chatroom Sip Servlet</description>

    <servlet-selection>
        <main-servlet>
            ChatroomSipServlet
        </main-servlet>
    </servlet-selection>
    <session-config>
        <session-timeout>5</session-timeout>
    </session-config>

    <servlet>
        <servlet-name>ChatroomSipServlet</servlet-name>
        <display-name>ChatroomSipServlet</display-name>
        <description>Chatroom SIP servlet</description>
        <servlet-class>
            sip.chatvoorbeeld.ChatroomSipServlet
        </servlet-class>
        <init-param>
            <param-name>chatroomservername</param-name>
            <param-value>sip:chatserver@192.168.56.1:5060</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
</sip-app>

I also tried an empty servlet, just with a doMessage() method that just prints out "message received". Same 32 seconds delay...

Wireshark gives me:

I send the message "test" to the server:

MESSAGE sip:chatserver@192.168.56.1:5060;transport=udp SIP/2.0
Call-ID: aba00c2646a9b4e6df3b15df19dbf58d@192.168.56.101
CSeq: 1 MESSAGE
From: "bobby" <sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
To: "chatserver" <sip:chatserver@192.168.56.1:5060>
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
Max-Forwards: 70
Contact: "bobby" <sip:bobby@192.168.56.101:5095>
Content-Type: text/plain
Content-Length: 4

test

Server sends back:

SIP/2.0 200 OK
Content-Length: 0
To: "chatserver"<sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-e
Cseq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
From: "bobby"<sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
Call-Id: aba00c2646a9b4e6df3b15df19dbf58d@192.168.56.101
Server: Glassfish_SIP_2.0.0

MESSAGE sip:bobby@192.168.56.101:5095 SIP/2.0
Max-Forwards: 69
Content-Length: 43
To: <sip:bobby@192.168.56.101:5095>
Cseq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.1:5060;branch=z9hG4bKdaacb7673c871796474ca951221a6643db6c
Content-Type: text/plain
Call-Id: 192.168.56.1_11_6595680936174578736
From: <sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-g

sip:bobby@192.168.56.101:5095 stuurt: 
test

Then my client again answers with an OK:

SIP/2.0 200 OK
To: <sip:bobby@192.168.56.101:5095>;tag=888
CSeq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.1:5060;branch=z9hG4bKdaacb7673c871796474ca951221a6643db6c;received=192.168.56.1
Call-ID: 192.168.56.1_11_6595680936174578736
From: <sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-g
Content-Length: 0

So far so good, everything works well. But now I send a second message to the server "test2" and I get this:

Client to server:

MESSAGE sip:chatserver@192.168.56.1:5060;transport=udp SIP/2.0
Call-ID: 95ad65365378b9b6b5bd7ad3629f7b02@192.168.56.101
CSeq: 1 MESSAGE
From: "bobby" <sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
To: "chatserver" <sip:chatserver@192.168.56.1:5060>
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
Max-Forwards: 70
Contact: "bobby" <sip:bobby@192.168.56.101:5095>
Content-Type: text/plain
Content-Length: 5

test2

Then the server does respond with:

SIP/2.0 200 OK
Content-Length: 0
To: "chatserver"<sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-e
Cseq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
From: "bobby"<sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
Call-Id: aba00c2646a9b4e6df3b15df19dbf58d@192.168.56.101
Server: Glassfish_SIP_2.0.0

But then the communication stops... I get a 200 OK, but the println() in my doMessage() method is not passed.

查看更多
聊天终结者
3楼-- · 2019-06-03 16:01

To answer my own question, if someone ever encounters the same problem, i found this is a bug in the textclient against the following section 8.1.1.7 of RFC 3261.

The branch parameter value MUST be unique across space and time for all requests sent by the UA. The exceptions to this rule are CANCEL and ACK for non-2xx responses. As discussed below, a CANCEL request will have the same value of the branch parameter as the request it cancels. As discussed in Section 17.1.1.3, an ACK for a non-2xx response will also have the same branch ID as the INVITE whose response it acknowledges.

The uniqueness property of the branch ID parameter, to facilitate its use as a transaction ID, was not part of RFC 2543.

The branch ID inserted by an element compliant with this specification MUST always begin with the characters "z9hG4bK".

The following line in SipLayer.java

ViaHeader viaHeader = headerFactory.createViaHeader(getHost(),
getPort(), "udp", "branch1");

Will create every message with the "branch1" parameter. Making this parameter unique fixes the problem.

查看更多
不美不萌又怎样
4楼-- · 2019-06-03 16:18

32 seconds is the normal timeout for transactions (denoted 64*T1 in RFC3261, where the default for T1 is 500ms.)

I have no direct idea for a solution to your problem, except that the timeout is very likely NOT a misconfiguration in SailFin. So please provide a wireshark trace and the server code!

查看更多
登录 后发表回答