如何拨打SIP电话
How do I do a SIP telephone call
我想在我的 java 应用程序中构造一个 telephone-caller。为此,我使用了 JAIN-SIP 库。在第一个 INVITE 之后,系统需要 Proxy-Authentication。第二个邀请是在 "AuthenticationHelperImpl.class":https://gitorious.org/0xdroid/external_nist-sip/source/1e0f37693341071f316852c8e05a08deef2b7fc4:java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java#L311 的帮助下构建的,包括 Proxy-Authentication header 和 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
之后我收到了代码 100 消息 ("your call is very important for us"),然后是 408 代码消息 ("Request Timeout")。
我做了什么来改善这种情况:
尝试了不同的 phone 数字格式:004930208488480,
04930208488480, 049, 0049, sdfhajfkhsk。对于所有这些数字,我
成为消息上的相同组合。
试图在请求 uri 中使用端口
试图从请求 uri 中删除 maddr。
尝试使用编码设置来填充消息 body。
通过 header
设置和删除 rport
如果你现在做错了,请帮助我。
提前谢谢你。
我想,也许你的Proxy-Authorizationheader是错误的。也许你失算了。我想分享我的决心。
authUser 是您的电话号码。 (例如: 77735hk6iu )
authPass 是您的用户密码。
msg 是您的邀请请求。(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;
}
获取授权函数:
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;
}
最后,您的 this.authentication 变量是 ProxyAuthorizationHeader。您必须将 this.authentication 放入您的 INVITE 消息中。然后,您会将 SipMessage 从事务或对话发送到 JAIN-SIP 堆栈。
祝你好运!
当从请求 URI 和代理验证中删除 "maddr=fpbx.de" 时,问题得到了部分解决。乌里
fpr 这是一个使用了布尔参数的 handleCahllenge 方法:
inviteTid = authenticationHelper.handleChallenge(response, tid, sipProvider, 15, **true**);
但我仍然不知道如何获得自发电话号码。
第100条消息是hop-by-hop,也就是说只是下一跳收到了你的请求。其他消息通常为 end-to-end(因此,如果您收到 180 振铃,这通常意味着被呼叫的端点发送了 180)。当其中一个跃点发送了 INVITE 但从未收到响应时,通常会出现 408(当您的 SIP 堆栈在合理的时间范围内未收到临时响应时,可能会在内部生成该响应——默认情况下通常约为 32 秒SIP 定时器)。
我不知道您的网络设置,但该邮件中有几个私有 IP(属于 192.168.x.x 种类)。如果我不得不猜测,你的第一跳是将 100 发送回它接收它的 IP/port,但下一个响应是在 Via headers 之后(应该如此),以及你之后的那一跳不遵守 rport 参数,因此响应丢失。或者,您的 NAT 配置不当,并且过快地关闭了它为 INVITE 创建的漏洞。
如果您的网络边缘有代理发送此消息,则它要么在消息上放置了错误的 Via headers(可能使用内部 IP 而不是外部 IP),要么它正在将 INVITE 发送到错误的地方(导致它永远得不到响应),而 408 就是来自它。
我想在我的 java 应用程序中构造一个 telephone-caller。为此,我使用了 JAIN-SIP 库。在第一个 INVITE 之后,系统需要 Proxy-Authentication。第二个邀请是在 "AuthenticationHelperImpl.class":https://gitorious.org/0xdroid/external_nist-sip/source/1e0f37693341071f316852c8e05a08deef2b7fc4:java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java#L311 的帮助下构建的,包括 Proxy-Authentication header 和 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
之后我收到了代码 100 消息 ("your call is very important for us"),然后是 408 代码消息 ("Request Timeout")。
我做了什么来改善这种情况:
尝试了不同的 phone 数字格式:004930208488480, 04930208488480, 049, 0049, sdfhajfkhsk。对于所有这些数字,我 成为消息上的相同组合。
试图在请求 uri 中使用端口
试图从请求 uri 中删除 maddr。
尝试使用编码设置来填充消息 body。
通过 header
设置和删除 rport
如果你现在做错了,请帮助我。 提前谢谢你。
我想,也许你的Proxy-Authorizationheader是错误的。也许你失算了。我想分享我的决心。
authUser 是您的电话号码。 (例如: 77735hk6iu ) authPass 是您的用户密码。 msg 是您的邀请请求。(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;
}
获取授权函数:
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;
}
最后,您的 this.authentication 变量是 ProxyAuthorizationHeader。您必须将 this.authentication 放入您的 INVITE 消息中。然后,您会将 SipMessage 从事务或对话发送到 JAIN-SIP 堆栈。
祝你好运!
当从请求 URI 和代理验证中删除 "maddr=fpbx.de" 时,问题得到了部分解决。乌里
fpr 这是一个使用了布尔参数的 handleCahllenge 方法:
inviteTid = authenticationHelper.handleChallenge(response, tid, sipProvider, 15, **true**);
但我仍然不知道如何获得自发电话号码。
第100条消息是hop-by-hop,也就是说只是下一跳收到了你的请求。其他消息通常为 end-to-end(因此,如果您收到 180 振铃,这通常意味着被呼叫的端点发送了 180)。当其中一个跃点发送了 INVITE 但从未收到响应时,通常会出现 408(当您的 SIP 堆栈在合理的时间范围内未收到临时响应时,可能会在内部生成该响应——默认情况下通常约为 32 秒SIP 定时器)。
我不知道您的网络设置,但该邮件中有几个私有 IP(属于 192.168.x.x 种类)。如果我不得不猜测,你的第一跳是将 100 发送回它接收它的 IP/port,但下一个响应是在 Via headers 之后(应该如此),以及你之后的那一跳不遵守 rport 参数,因此响应丢失。或者,您的 NAT 配置不当,并且过快地关闭了它为 INVITE 创建的漏洞。
如果您的网络边缘有代理发送此消息,则它要么在消息上放置了错误的 Via headers(可能使用内部 IP 而不是外部 IP),要么它正在将 INVITE 发送到错误的地方(导致它永远得不到响应),而 408 就是来自它。