public void init() {
try {
// Get the local IP address.
this.ip = InetAddress.getLocalHost().getHostAddress();
// Create the SIP factory and set the path name.
this.sipFactory = SipFactory.getInstance();
this.sipFactory.setPathName("gov.nist");
// Create and set the SIP stack properties.
this.properties = new Properties();
this.properties.setProperty("javax.sip.STACK_NAME", "stack");
this.properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
if(proxy != null) {
this.properties.setProperty("javax.sip.OUTBOUND_PROXY", proxy + ':' + port + '/' + protocol);
}
this.properties.setProperty(
"gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true");
this.properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
"mss-jsip-debuglog.txt");
this.properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
"mss-jsip-messages.xml");
// Create the SIP stack.
this.sipStack = this.sipFactory.createSipStack(this.properties);
// Create the SIP message factory.
this.messageFactory = this.sipFactory.createMessageFactory();
// Create the SIP header factory.
this.headerFactory = this.sipFactory.createHeaderFactory();
// Create the SIP address factory.
this.addressFactory = this.sipFactory.createAddressFactory();
// Create the SIP listening point and bind it to the local IP
// address, port and protocol.
this.listeningPoint = this.sipStack.createListeningPoint(this.ip,
this.port, this.protocol);
// Create the SIP provider.
this.sipProvider = this.sipStack
.createSipProvider(this.listeningPoint);
// Add our application as a SIP listener.
this.sipProvider.addSipListener(this);
// Create the contact address used for all SIP messages.
this.contactAddress = this.addressFactory.createAddress("sip:" + this.username + "@"
+ this.ip + ";transport=tcp");
// Create the contact header used for all SIP messages.
this.contactHeader = this.headerFactory
.createContactHeader(contactAddress);
// Display the local IP address and port in the text area.
} catch (Exception e) {
e.printStackTrace();
// If an error occurs, display an error message box and exit.
System.exit(-1);
}
}
Wednesday, April 10, 2013
Initializing NIST JAIN SIP Stack
Digest authorization in SIP with MD5 Challenge
The client should use nonce value from the response header WWW-Authenticate.
[code]
WWW-Authenticate: Digest realm="sip.linphone.org", nonce="JbAO1QAAAAA3aDI0AADMobiT7toAAAAA", opaque="+GNywA==", algorithm=MD5, qop="auth"
[/code]
The client should use nonce to generate the MD5 challenge and make the original request again with the Authorization header.
Steps to create the MD5 Challenge
1. Create first MD5 hash using username + ":" + realm + ":" + password
[java]
String a1 = username + ":" + realm + ":" + password;
String ha1 = toHexString(mdigest.digest(a1.getBytes()));
[/java]
2. Create second MD5 hash using request_method + ":" + request_uri
[java]
String a2 = request_method.toUpperCase() + ":" + request_uri;
String ha2 = toHexString(mdigest.digest(a2.getBytes()));
[/java]
3. If qop in the response header is "auth" then the final MD5 hash is calculated using step 3a else if it is undefined or empty refer step 3b.
3a. Create the final MD5 string using ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce + ":" + qop + ":" + ha2
[java]
String finalStr = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce + ":" + qop + ":" + ha2;
String response = toHexString(mdigest.digest(finalStr.getBytes()));
[/java]
3b. Create the final MD5 string using ha1 + ":" + nonce + ":" + ha2
[java]
String finalStr = ha1 + ":" + nonce + ":" + ha2;
String response = toHexString(mdigest.digest(finalStr.getBytes()));
[/java]
Download the complete source code from here
Tuesday, April 9, 2013
SIP Register Request using JAIN SIP
Note: To understand the Authorization process for handling 401 response code from server please go through this tutorial.
REGISTER request is used to update the current location of a user on the REGISTRAR server. The application sends a REGISTER message informing the server its current location which in turn is stored in location server. When a caller calls a user the proxy server uses this information to find the location of the callee.
Register request should be sent by the client periodically. The validity of the REGISTER request is determined by the Expires header.
Flow
Sample Request
[code]
REGISTER sip:sip.linphone.org SIP/2.0
Call-ID: 0a0f14355fa76ae6435b98bfe085baf9@223.1.1.128
CSeq: 1 REGISTER
From: <sip:vkslabs@sip.linphone.org>;tag=-1427592833
To: <sip:vkslabs@sip.linphone.org>
Max-Forwards: 70
Via: SIP/2.0/TCP 223.1.1.128:5060;branch=z9hG4bK-323532-2a454f4ec2a4213f6d6928eba479521d
Contact: <sip:vkslabs@223.1.1.128;transport=tcp>
Content-Length: 0
[/code]
Now lets see how to construct the above request using the NIST SIP Stack.
First step is to create a class that implements the SIPListener. Make sure your SIP Stack is Initializing NIST JAIN SIP Stack.
1. Create Call-ID header
[java] CallIdHeader callIdHeader = this.sipProvider.getNewCallId(); [/java]
2. Create CSeq header
[java] CSeqHeader cSeqHeader = this.headerFactory.createCSeqHeader(cseq, "REGISTER"); [/java]
3. Create From header
[java] Address fromAddress = addressFactory.createAddress("sip:" + username + '@' + server);
FromHeader fromHeader = this.headerFactory.createFromHeader(fromAddress, String.valueOf(this.tag));
[/java]
4. Create To Header
[java] ToHeader toHeader = this.headerFactory.createToHeader(fromAddress, null); [/java]
5. Create Max-Forwards header
[java] MaxForwardsHeader maxForwardsHeader = this.headerFactory.createMaxForwardsHeader(70); [/java]
6. Create a Via header
[java]
ArrayList viaHeaders = new ArrayList();
ViaHeader viaHeader = this.headerFactory.createViaHeader(this.ip, this.port, "tcp", null);
viaHeaders.add(viaHeader);
[/java]
7. Create contact header
[java]
this.contactAddress = this.addressFactory.createAddress("sip:" + this.username + '@' + this.ip + "transport=tcp");
// Create the contact header used for all SIP messages.
this.contactHeader = this.headerFactory.createContactHeader(contactAddress);
[/java]
Once all the headers are created it is time to create the request itself.
[java]
request = this.messageFactory.createRequest("REGISTER sip:" + server + "SIP/2.0\r\n\r\n");
request.addHeader(callIdHeader);
request.addHeader(cSeqHeader);
request.addHeader(fromHeader);
request.addHeader(toHeader);
request.addHeader(maxForwardsHeader);
request.addHeader(viaHeader);
request.addHeader(contactHeader);
[/java]
Now that the request object is created with all the necessary headers it is time to send the request.
[java] inviteTid = sipProvider.getNewClientTransaction(request);
// send the request out.
inviteTid.sendRequest();
[/java]
Once the request is sent successfully the response will be passed to the application using the processResponse callback in SIPListener.
[java]
public void processResponse(ResponseEvent responseEvent) {
int statusCode = responseEvent.getResponse().getStatusCode();
}
[/java]
Code
[java]
public void register(Response response) {
try {
cseq++;
ArrayList viaHeaders = new ArrayList();
ViaHeader viaHeader = this.headerFactory.createViaHeader(this.ip,
this.port, "tcp", null);
viaHeaders.add(viaHeader);
// The "Max-Forwards" header.
MaxForwardsHeader maxForwardsHeader = this.headerFactory
.createMaxForwardsHeader(70);
// The "Call-Id" header.
CallIdHeader callIdHeader = this.sipProvider.getNewCallId();
// The "CSeq" header.
CSeqHeader cSeqHeader = this.headerFactory.createCSeqHeader(cseq,
"REGISTER");
Address fromAddress = addressFactory.createAddress("sip:"
+ username + '@' + server);
FromHeader fromHeader = this.headerFactory.createFromHeader(
fromAddress, String.valueOf(this.tag));
// The "To" header.
ToHeader toHeader = this.headerFactory.createToHeader(fromAddress,
null);
// this.contactHeader = this.headerFactory
// .createContactHeader(contactAddress);
request = this.messageFactory.createRequest("REGISTER sip:"
+ server + " SIP/2.0\r\n\r\n");
request.addHeader(callIdHeader);
request.addHeader(cSeqHeader);
request.addHeader(fromHeader);
request.addHeader(toHeader);
request.addHeader(maxForwardsHeader);
request.addHeader(viaHeader);
request.addHeader(contactHeader);
if (response != null) {
retry = true;
AuthorizationHeader authHeader = Utils.makeAuthHeader(headerFactory, response,
request, username, password);
request.addHeader(authHeader);
}
inviteTid = sipProvider.getNewClientTransaction(request);
// send the request out.
inviteTid.sendRequest();
this.dialog = inviteTid.getDialog();
// Send the request statelessly through the SIP provider.
// this.sipProvider.sendRequest(request);
// Display the message in the text area.
logger.debug("Request sent:\n" + request.toString() + "\n\n");
} catch (Exception e) {
// If an error occurred, display the error.
e.printStackTrace();
logger.debug("Request sent failed: " + e.getMessage() + "\n");
}
}
[/java]
Download the complete working code from here.
Monday, April 8, 2013
Introduction to SIP
SIP stands for Session Initiation Protocol a signaling protocol defined by IETF used for controlling communication sessions. SIP is used to create, manage and terminate sessions in an IP based network. SIP is widely used in VOIP (Voice over IP) .
The two main entities in a SIP session are
User Agent Client
User Agent Server
There are several types of server
Proxy Server
Redirect Server
Registrar
Location Server
SIP is similar to HTTP protocol. To understand the differences lets first learn how HTTP Protocol works.
Here is a sample HTTP request
GET /index.html HTTP/1.1
Host: www.w3.org
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:20.0) Gecko/20100101 Firefox/20.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
The first line is the request line which has the request method (GET), the URI that is being requested (index.html) and the protocol version (HTTP/1.1)
Following the request line is one or more request headers like Host, User-Agent etc.
An empty line break follows the request headers which is followed an options message body.
Once you understand the protocol you can mimic a browser and send a request to web server using telnet or a simple java program that uses plain socket.
TBD
Now lets take a look at SIP protocol and find out the differences between HTTP and SIP
Here is a sample SIP request
REGISTER sip:ss2.biloxi.example.com SIP/2.0
Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7
Max-Forwards: 70
From: Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl
To: Bob <sips:bob@biloxi.example.com>
Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com
CSeq: 1 REGISTER
Contact: <sips:bob@client.biloxi.example.com>
Content-Length: 0
The first line is the request line which has the request method (REGISTER), the URI that is being requested (index.html) and the protocol version (HTTP/1.1)
Following the request line is one or more request headers like Host, User-Agent etc.
An empty line break follows the request headers which is followed an options message body.
Thursday, April 4, 2013
Capturing Android SIP Logs using TCPDump
1. Start adb in root mode by entering the following command
adb root
2. Download the tcpdump binary from either http://www.tcpdump.org or here
3. Push tcpdump to the device.
adb push tcpdump-arm /data/local/
4. Make sure correct permission is set for tcpdump.
adb shell chmod 777 /data/local/tcpdump-arm
5. Start capturing the network packets. Replace any with your interface name. In my case it was wlan0.
adb shell /data/local/tcpdump-arm -i any -p -s 0 -w /data/local/captured.pcap
6. Once the network packets are captured we can copy that back to your machine to view it in wireshark.
adb pull /data/local/captured.pcap
7. View the SIP packets in wireshark using the view filter.
Note: Wireshark can be downloaded from http://www.wireshark.org/download.html