How do I do a SIP telephone call - java

I want to constract a telephone-caller inside my java application. For this pupose I used a JAIN-SIP library. After the first INVITE the system needs Proxy-Authentication. The second invite is conscructed with the help of "AuthenticationHelperImpl.class":https://gitorious.org/0xdroid/external_nist-sip/source/1e0f37693341071f316852c8e05a08deef2b7fc4:java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java#L311, includes Proxy-Authentication header and lloks like:
INVITE sip:+11111111111#fpbx.de;maddr=fpbx.de SIP/2.0
Call-ID: 1c609509a43b721ab11c396c1e6ea9e7#192.168.17.107
CSeq: 2 INVITE
From: "77735hk6iu" <sip:77735hk6iu#fpbx.de>
To: "+111111111111111" <sip:+11111111111#fpbx.de>
Via: SIP/2.0/UDP 192.168.17.107:34567;rport;branch=z9hG4bK-383337-5bc4fd6b7a616843fce9eaa243bcb10e
Max-Forwards: 70
Contact: <sip:77735hk6iu#192.168.17.107:5060>
Content-Type: application/sdp
Proxy-Authorization: Digest username="77735hk6iu",realm="fpbx.de",nonce="VLaIxVS2h5muPS30F2zLdXHjup6ELyen",uri="sip:+111111111111#fpbx.de:5060;maddr=fpbx.de",response="47ea578c6b01c99fd3ed2b41c60983df"
Content-Length: 61
v=0
o=- 130565705777141827 1 IN IP4 192.168.17.107
s=call
After that I receive at the beginning code 100 message ("your call is very important for us") followed with 408 code message ("Request Timeout").
What I did to imporve the situation:
tried different phone number formats: 004930208488480,
04930208488480, 049, 0049, sdfhajfkhsk. For all these numbers I
become the same combination on messages.
tried to use port in request uri
tried to remove maddr from request uri.
tried to fullfill the message body with codek settings.
to set and remove rport from via header
If you now what I'm doing wrong, please, help me.
Thank you in advance.

I think, Maybe your Proxy-Authorization header is wrong. Maybe you is miscalculated. I wanted to share my resolve.
authUser is your phoneNumber. (for example: 77735hk6iu )
authPass is your user's password.
msg is your invite request.(Headers !)
AccountManagerImpl accountManagerImp = new AccountManagerImpl(authUser, AuthPass);
AuthenticationHelperImpl authenticationHelperImpl = new AuthenticationHelperImpl(accountManagerImp);
try {
this.authentication = authenticationHelperImpl.handleChallenge(msg, (SIPClientTransaction)trans);
AuthenticationHelperImple.java Class :
public AuthorizationHeader handleChallenge(Response challenge, ClientTransaction challengedTransaction) throws SipException {
SIPRequest challengedRequest = ((SIPRequest) challengedTransaction.getRequest());
ListIterator authHeaders = null;
if (challenge.getStatusCode() == Response.UNAUTHORIZED) {
authHeaders = challenge.getHeaders(WWWAuthenticateHeader.NAME);
}
else {
if (challenge.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED) {
authHeaders = challenge.getHeaders(ProxyAuthenticateHeader.NAME);
}
else {
throw new IllegalArgumentException("Unexpected status code ");
}
}
if (authHeaders == null) {
throw new IllegalArgumentException("Could not find WWWAuthenticate or ProxyAuthenticate headers");
}
WWWAuthenticateHeader authHeader = null;
while (authHeaders.hasNext()) {
authHeader = (WWWAuthenticateHeader) authHeaders.next();
String realm = authHeader.getRealm();
this.uri = challengedRequest.getRequestURI();
this.requestMethod = challengedRequest.getMethod();
this.requestBody = (challengedRequest.getContent() == null) ? "" : new String(challengedRequest.getRawContent());
if (this.accountManager instanceof SecureAccountManager) {
UserCredentialHash credHash = ((SecureAccountManager) this.accountManager).getCredentialHash(challengedTransaction,
realm);
if (credHash == null) {
logger.logDebug("Could not find creds");
throw new SipException("Cannot find user creds for the given user name and realm");
}
this.authorizationHeader = this.getAuthorization(requestMethod, uri.toString(), requestBody, authHeader, credHash);
}
else {
UserCredentials userCreds = ((AccountManager) this.accountManager).getCredentials(challengedTransaction, realm);
if (userCreds == null) {
throw new SipException("Cannot find user creds for the given user name and realm");
}
// sipDomain = userCreds.getSipDomain();
// we haven't yet authenticated this realm since we were
// started.
this.authorizationHeader = this.getAuthorization(requestMethod, uri.toString(), requestBody, authHeader, userCreds);
}
}
return this.authorizationHeader;
}
getAuthorization function :
public AuthorizationHeader getAuthorization(String method,
String uri,
String requestBody,
WWWAuthenticateHeader authHeader,
UserCredentials userCredentials) throws SecurityException {
String response = null;
String qopList = authHeader.getQop();
String qop = (qopList != null) ? "auth" : null;
String nc_value = "00000001";
String cnonce = "xyz";
try {
response = MessageDigestAlgorithm.calculateResponse(authHeader.getAlgorithm(),
userCredentials.getUserName(), authHeader.getRealm(),userCredentials.getPassword(), authHeader.getNonce(), nc_value, // JvB added
cnonce, // JvB added
method, uri, requestBody, qop,logger);
}
catch (NullPointerException exc) {
throw new SecurityException("The received authenticate header was malformatted: " + exc.getMessage());
}
AuthorizationHeader authorization = null;
try {
if (authHeader instanceof ProxyAuthenticateHeader) {
if (this.headerFactory != null) {
authorization = headerFactory.createProxyAuthorizationHeader(authHeader.getScheme());
}
else {
authorization = new ProxyAuthorization();
authorization.setScheme(authHeader.getScheme());
}
}
else {
if (this.headerFactory != null) {
authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme());
}
else {
authorization = new Authorization();
authorization.setScheme(authHeader.getScheme());
}
}
authorization.setUsername(userCredentials.getUserName());
authorization.setRealm(authHeader.getRealm());
authorization.setNonce(authHeader.getNonce());
authorization.setParameter("uri", uri);
authorization.setResponse(response);
if (authHeader.getAlgorithm() != null) {
authorization.setAlgorithm(authHeader.getAlgorithm());
}
if (authHeader.getOpaque() != null) {
authorization.setOpaque(authHeader.getOpaque());
}
// jvb added
if (qop != null) {
authorization.setQop(qop);
authorization.setCNonce(cnonce);
authorization.setNonceCount(Integer.parseInt(nc_value));
}
authorization.setResponse(response);
} catch (ParseException ex) {
throw new RuntimeException("Failed to create an authorization header!");
}
return authorization;
}
Finally, your this.authentication variable is ProxyAuthorizationHeader. You must put this.authentication in your INVITE message. And than you will sent SipMessage from transaction or dialog to JAIN-SIP stack.
Good Luck !

The problem was partly solved when a removed "maddr=fpbx.de" from request URI and from proxy-auth. uri
fpr this a used handleCahllenge method with boolean arguments:
inviteTid = authenticationHelper.handleChallenge(response, tid, sipProvider, 15, **true**);
But I still don't know how I can a acchieve sponaneous telephone number.

The 100 message is hop-by-hop, that is to say it just means the next hop got your request. Other messages will typically be end-to-end (so, if you got a 180 Ringing, that typically means the endpoint being called sent the 180). A 408 typically shows up when one of the hops sent the INVITE but never got a response (and your SIP stack might be generating that internally when it doesn't get a provisional response in a reasonable timeframe -- usually about 32 seconds with the default SIP timers).
I don't know your network setup, but there are several private IPs in that message (of the 192.168.x.x variety). If I had to guess, your first hop is sending the 100 back to the IP/port it received it from, but the next response is following the Via headers (as it should), and the hop after you isn't respecting the rport parameter, so the response is getting lost. Alternately, your NAT is poorly configured and is closing the hole it created for the INVITE too quickly.
If you have a proxy on the edge of your network that this message is going out, it is either putting bad Via headers on the message (possibly with the internal IP instead of the external IP) or it is sending the INVITE to the wrong place (causing it to never get a response), and the 408 is coming from it.

Related

Why do I get OAuthProblemException error='invalid_request' description='Handle could not be extracted' when doing Exact OAuth

When doing calls to Exact-on-line API to get authenticated we run into the problem that getting the first refresh-token fails. We're not sure why. This is what we get back from Exact:
Http code: 400
JSON Data:
{
error='invalid_request',
description='Handle could not be extracted',
uri='null',
state='null',
scope='null',
redirectUri='null',
responseStatus=400,
parameters={}
}
We use this Java code based on library org.apache.oltu.oauth2.client (1.0.2):
OAuthClientRequest oAuthRequest = OAuthClientRequest //
.tokenLocation(BASE_URL + "/api/oauth2/token") //
.setGrantType(GrantType.AUTHORIZATION_CODE) //
.setClientId(clientId) //
.setClientSecret(clientSecret) //
.setRedirectURI(REDIRECT_URI) //
.setCode(code) //
.buildBodyMessage();
OAuthClient client = new OAuthClient(new URLConnectionClient());
OAuthJSONAccessTokenResponse oauthResponse = client.accessToken(oAuthRequest, OAuth.HttpMethod.POST);
We did do the first step (getting the 'code' as used in setCode(...)) using a localhost-redirect as displayed in https://support.exactonline.com/community/s/knowledge-base#All-All-DNO-Content-gettingstarted There we copy the code from the address-bar of our browser and store it in a place the next computer-step can read it again.
This is due to the fact that the code was copied from your browsers address-bar. There you will find a URL-encoded version of the code (visible in the '%21' often) which when passed into the setCode verbatim will fail the subsequent calls.
Suggestion: URL-decode the value or setup a small temporary localhost-HTTP-server using Undertow or the like to catch the code that was send to you localhost-URL:
Undertow server = Undertow.builder() //
.addHttpListener(7891, "localhost") //
.setHandler(new HttpHandler() {
#Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
String code = exchange.getQueryParameters().get("code").getFirst();
LOG.info("Recieved code: {}.", code);
LOG.info("Store code");
storeCode(code);
LOG.info("Code stored");
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send( //
"Thanks for getting me the code: " + code + "\n" //
+ "Will store it for you and get the first refreshToken..." //
+ "Please have a look at " + OAUTH_STATE_INI
+ " for the new code & refreshToken in a minute" //
);
done.add("done");
}
}).build();
server.start();
NB: Do make sure the redirect URL is correct in your Exact-app-settings

Java mail don't return subject

I'm using javamail to rescue mails of inbox. I get all mails from inbox, but the subject(message.getSubject()) return null.
I research in several sites and all proposed solutions not work.
This problem occurs only in the Tomcat6, if a execute even code in java project for main method i get all atributis, include subject. I'm user de SSL protocol (pop3s).
Thanks for help
public void getMails(final String host, final int port, final String user, final String password){
final Session session = Session.getInstance(System.getProperties(), null);
final Store store = session.getStore("pop3s");
store.connect(host, port, user, password);
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);
int count = inbox.getMessageCount();
System.out.println(" Count Emails "+count);
final Message[] messages = inbox.getMessages();
for (final Message message : messages) {
//This return null
System.out.print("mail subject: " + message.getSubject() + " send at: " + message.getSentDate());
//This return body of mail
System.out.print("mail subject: " + message.getContent().toString());
}
My output for the method Main directly on eclipse:
MessageCount: 4
full name: INBOX
NewMessageCount: 0
getDescription: null
getFileName: null
getMessageNumber: 1
getSize: 2297
getSentDate: Mon Aug 03 17:23:10 BRT 2015
from: Silvano Wojczak silvano.wojczak#softexpertjlle.onmicrosoft.com
Content: javax.mail.internet.MimeMultipart#6769ba97
Content getClass: class javax.mail.internet.MimeMultipart
For log4j in TomCat6:
MessageCount: 4
full name: INBOX
NewMessageCount: 0
getDescription: null
getFileName: null
getMessageNumber: 1
getSize: 6731
getSentDate: null
from: null
Content: javax.mail.internet.MimeMultipart#6769ba97
Content getClass: class javax.mail.internet.MimeMultipart
It seems to me that the runtime of your installation of Tomcat 6 has its own implementation of JavaMail.
You'd better ensure first which implementation of JavaMail are you using actually. Execute this scrap in the same program that reads the mail, immediately before the error occurs:
String packageName="javax.mail.internet.";
String simpleClassName="MimeMultipart";
String className=packageName+simpleClassName;
Class<?> cl=Class.forName(className);
URL url=cl.getResource(simpleClassName+".class");
System.out.println("url="+url);
Once I suffered this kind of problems when using older implementations of geronimo-mail, and I got to solved them by cloning the message before reading the headers:
private static MimeMessage cloneMimeMessage(Session session, MimeMessage src)
throws MessagingException
{
if (src instanceof POP3Message)
{
return new MimeMessage(session, ((POP3Message)src).top(Integer.MAX_VALUE));
}
else if (src instanceof IMAPMessage)
{
return new MimeMessage(session, ((IMAPMessage)src).getRawInputStream());
}
else
{
throw new UnsupportedOperationException();
}
}

PUSH Notifications for >1000 devices through GCM Server(Java)

I have a GCM-backend Java server and I'm trying to send to all users a notification msg. Is my approach right? To just split them into 1000 each time before giving the send request? Or is there a better approach?
public void sendMessage(#Named("message") String message) throws IOException {
int count = ofy().load().type(RegistrationRecord.class).count();
if(count<=1000) {
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(count).list();
sendMsg(records,message);
}else
{
int msgsDone=0;
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).list();
do {
List<RegistrationRecord> regIdsParts = regIdTrim(records, msgsDone);
msgsDone+=1000;
sendMsg(regIdsParts,message);
}while(msgsDone<count);
}
}
The regIdTrim method
private List<RegistrationRecord> regIdTrim(List<RegistrationRecord> wholeList, final int start) {
List<RegistrationRecord> parts = wholeList.subList(start,(start+1000)> wholeList.size()? wholeList.size() : start+1000);
return parts;
}
The sendMsg method
private void sendMsg(List<RegistrationRecord> records,#Named("message") String message) throws IOException {
if (message == null || message.trim().length() == 0) {
log.warning("Not sending message because it is empty");
return;
}
Sender sender = new Sender(API_KEY);
Message msg = new Message.Builder().addData("message", message).build();
// crop longer messages
if (message.length() > 1000) {
message = message.substring(0, 1000) + "[...]";
}
for (RegistrationRecord record : records) {
Result result = sender.send(msg, record.getRegId(), 5);
if (result.getMessageId() != null) {
log.info("Message sent to " + record.getRegId());
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// if the regId changed, we have to update the datastore
log.info("Registration Id changed for " + record.getRegId() + " updating to " + canonicalRegId);
record.setRegId(canonicalRegId);
ofy().save().entity(record).now();
}
} else {
String error = result.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
log.warning("Registration Id " + record.getRegId() + " no longer registered with GCM, removing from datastore");
// if the device is no longer registered with Gcm, remove it from the datastore
ofy().delete().entity(record).now();
} else {
log.warning("Error when sending message : " + error);
}
}
}
}
Quoting from Google Docs:
GCM is support for up to 1,000 recipients for a single message. This capability makes it much easier to send out important messages to your entire user base. For instance, let's say you had a message that needed to be sent to 1,000,000 of your users, and your server could handle sending out about 500 messages per second. If you send each message with only a single recipient, it would take 1,000,000/500 = 2,000 seconds, or around half an hour. However, attaching 1,000 recipients to each message, the total time required to send a message out to 1,000,000 recipients becomes (1,000,000/1,000) / 500 = 2 seconds. This is not only useful, but important for timely data, such as natural disaster alerts or sports scores, where a 30 minute interval might render the information useless.
Taking advantage of this functionality is easy. If you're using the GCM helper library for Java, simply provide a List collection of registration IDs to the send or sendNoRetry method, instead of a single registration ID.
We can not send more than 1000 push notification at time.I searched a lot but not result then i did this with same approach split whole list in sub lists of 1000 items and send push notification.

HtmlUnit webpage status code

I am trying to get the web status for a given page. However when its a 404 error, the page does not return the status code, rather it throws and error.
int status= webClient.getPage("website").getWebResponse().getStatusCode();
System.out.println( status);
Any Ideas?
I am looking to see when sites time out, however for testing purposes I malformed the url of the desired website to see if I can even see a 404.
According to this
You can do this:
webclient.setThrowExceptionOnFailingStatusCode(False)
****EDIT ***
This does print out your status code:
WebClient webClient = new WebClient();
webClient.setThrowExceptionOnFailingStatusCode(false);
int status = webClient.getPage("http://google.co.uk/ffffff").getWebResponse()
.getStatusCode();
System.out.println(status);
Prints out 404 - your status code.
Alternatively, you can continue to allow the FailingHttpStatusCodeException to be thrown (true). Then within the catch clause get the error status code.
...
int status = 0;
Object page = null;
try {
page = webClient.getPage(webRequest);
webClient.close();
if (page instanceof UnexpectedPage) {
status = ((UnexpectedPage) page).getWebResponse().getStatusCode();
} else if (page instanceof HtmlPage) {
status = ((HtmlPage) page).getWebResponse().getStatusCode();
}
// do something else ...
} catch (FailingHttpStatusCodeException | IOException e) {
if (e instanceof FailingHttpStatusCodeException) {
status = ((FailingHttpStatusCodeException) e).getStatusCode();
}
// do something else ...
}

How to get error-response packet from apple's Enhanced notification format with javapns

ResponsePacket theErrorResponse = pushedNotification.getResponse();I'm using javapns2.2 and trying to catch error-response packet from from apple's Enhanced notification format. When I send push notification (with invalid token for example) the code
Exception theProblem = pushedNotification.getException();
theProblem.printStackTrace();
outputs some error to the console, but
ResponsePacket theErrorResponse = pushedNotification.getResponse();
if (theErrorResponse != null && theErrorResponse.isErrorResponsePacket()) {
System.out.println(theErrorResponse.getMessage());
System.out.println(theErrorResponse.getStatus());
}
always returns null. How can I obtain status codes with getResponse()?
Here is a part of my code:
List<PushedNotification> notifications = Push.payload(payload, keystore, password, production, devices);
for (PushedNotification pushedNotification : notifications) {
if(pushedNotification.isSuccessful())
{
System.out.println(pushedNotification.getDevice().getToken());
}
else
{
System.out.println(pushedNotification.getDevice().getToken());
Exception theProblem = pushedNotification.getException();
theProblem.printStackTrace();
ResponsePacket theErrorResponse = pushedNotification.getResponse();
if (theErrorResponse != null && theErrorResponse.isErrorResponsePacket()) {
System.out.println(theErrorResponse.getMessage());
System.out.println(theErrorResponse.getStatus());
}
}
}
Thank you for your help
I figured it out.
getResponse() returns null because Exception mechanism is preventing the call to APNs to be more efficient. True errors are packed within Exception mechanism.
Everything is super explained at this link:
http://code.google.com/p/javapns/issues/detail?id=79&can=1

Categories