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
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.
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!
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.