master moved from 25843dadefaa to 80d406972ece
2 new revisions:
Revision: 31b692f3a99d
Author: dmisol <[email protected]>
Date: Fri Aug 16 18:40:11 2013 UTC
Log: coding call setup
http://code.google.com/p/isup2sip/source/detail?r=31b692f3a99d
Revision: 80d406972ece
Author: dmisol <[email protected]>
Date: Mon Aug 19 18:23:33 2013 UTC
Log: still coding
http://code.google.com/p/isup2sip/source/detail?r=80d406972ece
==============================================================================
Revision: 31b692f3a99d
Author: dmisol <[email protected]>
Date: Fri Aug 16 18:40:11 2013 UTC
Log: coding call setup
http://code.google.com/p/isup2sip/source/detail?r=31b692f3a99d
Modified:
/core/bootstrap/src/main/config/META-INF/jboss-beans.xml
/core/domain/src/main/java/org/mobicents/isup2sip/management/CicManagement.java
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipPropertiesManagement.java
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipPropertiesManagementMBean.java
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipShellExecutor.java
/core/slee/sbbs/src/main/java/org/mobicents/isup2sip/sbb/Isup2SipSbb.java
/core/slee/sbbs/src/main/resources/META-INF/sbb-jar.xml
=======================================
--- /core/bootstrap/src/main/config/META-INF/jboss-beans.xml Sun Aug 4
00:08:46 2013 UTC
+++ /core/bootstrap/src/main/config/META-INF/jboss-beans.xml Fri Aug 16
18:40:11 2013 UTC
@@ -122,14 +122,11 @@
<parameter>Isup2SipManagement</parameter>
</constructor>
<property name="persistDir">${jboss.server.data.dir}</property>
-<!-- <property name="gateway">192.168.1.13:2427</property>
- <property name="remoteSPC">222</property>-->
</bean>
-<!-- <bean name="Isup2SipShellExecutor"
class="org.mobicents.isup2sip.domain.Isup2SipShellExecutor">
- <property name="isup2sipManagement">
+- <bean name="Isup2SipShellExecutor"
class="org.mobicents.isup2sip.management.Isup2SipShellExecutor">
+ <property name="isup2SipManagement">
<inject bean="Isup2SipManagement" />
</property>
</bean>
--->
</deployment>
=======================================
---
/core/domain/src/main/java/org/mobicents/isup2sip/management/CicManagement.java
Sat Aug 3 10:50:58 2013 UTC
+++
/core/domain/src/main/java/org/mobicents/isup2sip/management/CicManagement.java
Fri Aug 16 18:40:11 2013 UTC
@@ -55,6 +55,9 @@
}
}
+ public Channel getChannelByCic(int cic) {
+ return channelByCic.get(cic);
+ }
public void setIdle(int cic) {
synchronized (synchCic) {
try {
=======================================
---
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipPropertiesManagement.java
Sun Aug 4 00:08:46 2013 UTC
+++
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipPropertiesManagement.java
Fri Aug 16 18:40:11 2013 UTC
@@ -43,7 +43,11 @@
protected static final String GATEWAY = "gateway";
protected static final String GATEWAY_PART = "part";
protected static final String REMOTE_PC = "remote";
-
+ protected static final String SIP_PEER = "sipPeer";
+ protected static final String SIP_IP = "sipIp";
+
+ public static final String ISUP_TO_SIP = "i2s";
+ public static final String SIP_TO_ISUP = "s2i";
private static final String TAB_INDENT = "\t";
private static final String CLASS_ATTRIBUTE = "type";
@@ -58,8 +62,22 @@
private final TextBuilder persistFile = TextBuilder.newInstance();
+ /**
+ * in release, there will be multiple gateways supported,
+ * each CIC will be mapped to some Endpoint @ some gateway
+ */
private String gateway;
+
+ /** in ISUP->SIP case, this peer will get all calls
+ *
+ */
+ private String sipPeer;
+
+ private String sipIp;
+ /** during developing, a single Telscale Card is shared between 2
isup2sip instances,
+ * that are running one agains another
+ */
private int gatewayPartForDebug;
// private DataSource dataSource;
@@ -126,7 +144,25 @@
this.gateway = gw;
}
-
+ @Override
+ public String getSipPeer(){
+ return this.sipPeer;
+ }
+
+ @Override
+ public void setSipPeer(String peer){
+ this.sipPeer = peer;
+ }
+
+ @Override
+ public String getSipIp(){
+ return this.sipIp;
+ }
+
+ @Override
+ public void setSipIp(String ip){
+ this.sipIp = ip;
+ }
@Override
public String getPersistDir() {
@@ -193,8 +229,12 @@
writer.write(this.gateway, GATEWAY, String.class);
writer.write(this.gatewayPartForDebug, GATEWAY_PART,
Integer.class);
writer.write(this.remoteSPC, REMOTE_PC, Integer.class);
-
+ writer.write(this.sipIp, SIP_IP, String.class);
+ writer.write(this.sipPeer, SIP_PEER, String.class);
+
writer.close();
+
+ logger.error("sipIp=" + this.sipIp + ", sipPeer=" +
this.sipPeer);
} catch (Exception e) {
logger.error("Error while persisting the Rule state in
file", e);
}
@@ -216,8 +256,8 @@
this.gateway = reader.read(GATEWAY, String.class);
this.gatewayPartForDebug = reader.read(GATEWAY_PART,
Integer.class);
this.remoteSPC = reader.read(REMOTE_PC, Integer.class);
-
-
+ this.sipIp = reader.read(SIP_IP, String.class);
+ this.sipPeer = reader.read(SIP_PEER, String.class);
reader.close();
} catch (XMLStreamException ex) {
=======================================
---
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipPropertiesManagementMBean.java
Sun Aug 4 00:08:46 2013 UTC
+++
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipPropertiesManagementMBean.java
Fri Aug 16 18:40:11 2013 UTC
@@ -37,4 +37,11 @@
public void setGateway(String gw);
+ public String getSipPeer();
+
+ public void setSipPeer(String peer);
+
+ public String getSipIp();
+
+ public void setSipIp(String ip);
}
=======================================
---
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipShellExecutor.java
Sun Aug 4 00:08:46 2013 UTC
+++
/core/domain/src/main/java/org/mobicents/isup2sip/management/Isup2SipShellExecutor.java
Fri Aug 16 18:40:11 2013 UTC
@@ -34,7 +34,7 @@
private static final Logger logger =
Logger.getLogger(Isup2SipShellExecutor.class);
- private Isup2SipManagement isup2sipManagement;
+ private Isup2SipManagement isup2SipManagement;
private Isup2SipPropertiesManagement isup2sipPropertiesManagement =
Isup2SipPropertiesManagement.getInstance();
/**
@@ -45,11 +45,11 @@
}
public Isup2SipManagement getIsup2SipManagement() {
- return isup2sipManagement;
+ return isup2SipManagement;
}
public void setIsup2SipManagement(Isup2SipManagement
isup2sipManagement) {
- this.isup2sipManagement = isup2sipManagement;
+ this.isup2SipManagement = isup2sipManagement;
}
/*
@@ -111,6 +111,8 @@
isup2sipPropertiesManagement.setGatewayPart(Integer.parseInt(options[3]));
} else if
(parName.equals(Isup2SipPropertiesManagement.REMOTE_PC)) {
isup2sipPropertiesManagement.setRemoteSPC(Integer.parseInt(options[3]));
+ } else if
(parName.equals(Isup2SipPropertiesManagement.SIP_PEER)) {
+ isup2sipPropertiesManagement.setSipPeer(options[3]);
} else {
return Isup2SipOAMMessages.INVALID_COMMAND;
}
@@ -138,6 +140,8 @@
sb.append(Integer.toString(isup2sipPropertiesManagement.getGatewayPart()));
} else if
(parName.equals(Isup2SipPropertiesManagement.REMOTE_PC)) {
sb.append(Integer.toString(isup2sipPropertiesManagement.getRemoteSPC()));
+ } else if
(parName.equals(Isup2SipPropertiesManagement.SIP_PEER)) {
+
sb.append(isup2sipPropertiesManagement.getSipPeer());
} else {
return Isup2SipOAMMessages.INVALID_COMMAND;
}
@@ -155,6 +159,10 @@
sb.append(Isup2SipPropertiesManagement.REMOTE_PC + " =
");
sb.append(Integer.toString(isup2sipPropertiesManagement.getRemoteSPC()));
+ sb.append(", ");
+
+ sb.append(Isup2SipPropertiesManagement.SIP_PEER + " =
");
+ sb.append(isup2sipPropertiesManagement.getSipPeer());
sb.append("\n");
return sb.toString();
=======================================
---
/core/slee/sbbs/src/main/java/org/mobicents/isup2sip/sbb/Isup2SipSbb.java
Sun Aug 4 00:08:46 2013 UTC
+++
/core/slee/sbbs/src/main/java/org/mobicents/isup2sip/sbb/Isup2SipSbb.java
Fri Aug 16 18:40:11 2013 UTC
@@ -33,6 +33,8 @@
import jain.protocol.ip.mgcp.message.parms.ReturnCode;
import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
@@ -40,17 +42,24 @@
import javax.sip.ClientTransaction;
import javax.sip.DialogState;
import javax.sip.InvalidArgumentException;
+import javax.sip.ListeningPoint;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
+import javax.sip.address.Address;
+import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.address.URI;
import javax.sip.header.CSeqHeader;
+import javax.sip.header.CallIdHeader;
+import javax.sip.header.ContactHeader;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderFactory;
+import javax.sip.header.MaxForwardsHeader;
import javax.sip.header.ToHeader;
+import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
@@ -82,6 +91,7 @@
import org.mobicents.protocols.ss7.isup.message.InitialAddressMessage;
import org.mobicents.protocols.ss7.isup.message.ReleaseCompleteMessage;
import org.mobicents.protocols.ss7.isup.message.ReleaseMessage;
+import
org.mobicents.protocols.ss7.isup.message.parameter.BackwardCallIndicators;
import
org.mobicents.protocols.ss7.isup.message.parameter.CalledPartyNumber;
import
org.mobicents.protocols.ss7.isup.message.parameter.CallingPartyCategory;
import
org.mobicents.protocols.ss7.isup.message.parameter.CallingPartyNumber;
@@ -129,14 +139,15 @@
// Initial request
public void onInviteEvent(RequestEvent sipEvent, ActivityContextInterface
aci) {
- if(this.getSipEvent() != null){
+ if(this.getConversionType() != null){
tracer.warning("Re-Invite event");
onReInviteEvent(sipEvent, aci);
return;
}
- tracer.warning("(primary) Invite event");
+ tracer.warning("(primary) Invite event, uri is " +
sipEvent.getRequest().getRequestURI() + "---");
this.setSipEvent(sipEvent);
+
this.setConversionType(Isup2SipPropertiesManagement.SIP_TO_ISUP);
// ACI is the server transaction activity
try {
@@ -172,7 +183,7 @@
// TODO Auto-generated catch block
e.printStackTrace();
}
- int txID = mgcpProvider.getUniqueTransactionHandler();
+ final int txID =
mgcpProvider.getUniqueTransactionHandler();
createConnection.setTransactionHandle(txID);
MgcpConnectionActivity connectionActivity = null;
@@ -199,34 +210,54 @@
}
}
+ // Initial request
public void onIAM(InitialAddressMessage iam, ActivityContextInterface
aci){
tracer.warning("isup IAM " +
iam.getCircuitIdentificationCode().getCIC());
- int cic = iam.getCircuitIdentificationCode().getCIC();
+ final int cic = iam.getCircuitIdentificationCode().getCIC();
+ final SbbLocalObject sbbLocalObject =
sbbContext.getSbbLocalObject();
+ final Channel channel = cicManagement.getChannelByCic(cic);
+
this.setCicValue(cic);
+
this.setConversionType(Isup2SipPropertiesManagement.ISUP_TO_SIP);
+ this.setANumber(iam.getCallingPartyNumber().getAddress());
+ this.setBNumber(iam.getCalledPartyNumber().getAddress());
+
+ if(channel == null) {
+ tracer.severe("not equipped CIC=" + cic);
+ // TO DO: terminate a call properly
+ }
showMe();
-
if(! cicManagement.setBusy(this.getCicValue())){
// stop a call.
- tracer.warning("CIC is not idle");
-
+ tracer.warning("CIC is not idle");
}
- // just dummy code now
- AddressCompleteMessage msg =
isupMessageFactory.createACM(this.getCicValue());
- msg.setSls(this.getCicValue());
-
- try {
- CircuitActivity circuitActivity =
isupProvider.createCircuitActivity(msg,remoteSPC);
- ActivityContextInterface cicAci =
isupActivityContextInterfaceFactory.getActivityContextInterface(circuitActivity);
- cicAci.attach(sbbContext.getSbbLocalObject());
- circuitActivity.sendMessage(msg);
-
-// isupProvider.sendMessage(msg,remoteSPC);
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
+
+ CallIdentifier mgcpCallID =
mgcpProvider.getUniqueCallIdentifier();
+ this.setMgcpCallIdentifier(mgcpCallID.toString());
+ EndpointIdentifier endpointID = new
EndpointIdentifier(channel.getEndpointId(),channel.getGatewayAddress());
+ CreateConnection createConnection = new CreateConnection(this,
+ mgcpCallID, endpointID,
ConnectionMode.SendRecv);
+
+ final int txID = mgcpProvider.getUniqueTransactionHandler();
+ createConnection.setTransactionHandle(txID);
+
+ MgcpConnectionActivity connectionActivity = null;
+ try {
+ connectionActivity = mgcpProvider.getConnectionActivity(txID,
endpointID);
+ ActivityContextInterface epnAci =
mgcpActivityContestInterfaceFactory.getActivityContextInterface(connectionActivity);
+ epnAci.attach(sbbLocalObject);
+ } catch (FactoryException ex) {
+ ex.printStackTrace();
+ } catch (NullPointerException ex) {
+ ex.printStackTrace();
+ } catch (UnrecognizedActivityException ex) {
+ ex.printStackTrace();
+ }
+
+ mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] {
createConnection });
+ tracer.info("ISUP->SIP, CRCX sent; ep ID=" + endpointID + " sbb=" +
sbbLocalObject);
}
@@ -241,8 +272,8 @@
cicManagement.setAnswered(this.getCicValue());
}
- public void onACM(AddressCompleteMessage isupEvent,
ActivityContextInterface aci){
- tracer.warning("isup ACM");
+ public void onACM(AddressCompleteMessage acm, ActivityContextInterface
aci){
+ tracer.warning("isup ACM " +
acm.getCircuitIdentificationCode().getCIC());
showMe();
sipReplyToRequestEvent(this.getSipEvent(), Response.RINGING);
@@ -251,108 +282,38 @@
}
public void onREL(ReleaseMessage rel, ActivityContextInterface aci){
- tracer.warning("isup REL");
+ tracer.warning("isup REL " +
rel.getCircuitIdentificationCode().getCIC());
showMe();
+
+ ReleaseCompleteMessage msg =
isupMessageFactory.createRLC(this.getCicValue());
+ msg.setSls(this.getCicValue());
+
+ try {
+ // just to play with stack, send smth
+ isupProvider.sendMessage(msg,remoteSPC);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
}
- public void onRLC(ReleaseCompleteMessage isupEvent,
ActivityContextInterface aci){
- tracer.warning("isup REL");
+ public void onRLC(ReleaseCompleteMessage rlc, ActivityContextInterface
aci){
+ tracer.warning("isup RLC " +
rlc.getCircuitIdentificationCode().getCIC());
showMe();
}
-
+// generic MGCP responces
public void onCreateConnectionResponse(CreateConnectionResponse event,
ActivityContextInterface aci) {
- tracer.info("CRCX RESP sbb=" + sbbContext.getSbbLocalObject());
-
- ReturnCode status = event.getReturnCode();
- boolean connectionCreated = (status.getValue() ==
ReturnCode.TRANSACTION_EXECUTED_NORMALLY);
- String sdp = null;
-
- if(connectionCreated) {
- sdp = event.getLocalConnectionDescriptor().toString();
- connectionCreated = (sdp!=null);
- }
- if(connectionCreated){
- /* the following should be done:
- * (1) SIP: send progress with sdp
- * (2) ISUP: send invite
- */
- ContentTypeHeader contentType = null;
- try {
- contentType =
headerFactory.createContentTypeHeader("application", "sdp");
- } catch (ParseException ex) {}
-
- Response response = null;
- try {
- response = messageFactory.createResponse(Response.SESSION_PROGRESS,
getSipEvent().getRequest(), contentType, sdp.getBytes());
- } catch (ParseException ex) {
- tracer.warning("ParseException while trying to create SESSION_PROGRESS
Response", ex);
- }
-
- // fetch A- and B- numbers
- Request sipRequest = this.getSipEvent().getRequest();
- FromHeader fromHeader = (FromHeader)
sipRequest.getHeader(FromHeader.NAME);
- ToHeader toHeader = (ToHeader)
sipRequest.getHeader(ToHeader.NAME);
- final String aNumber =
CodingShemes.numberFromURI(fromHeader.getAddress().getURI().toString());
- final String bNumber =
CodingShemes.numberFromURI(toHeader.getAddress().getURI().toString());
- tracer.warning("To header=" + toHeader + " ->" +
bNumber);
- tracer.warning("From header=" + fromHeader + " ->" +
aNumber);
-
- InitialAddressMessage msg =
isupMessageFactory.createIAM(this.getCicValue());
-// CircuitIdentificationCode cic =
isupParameterFactory.createCircuitIdentificationCode();
- NatureOfConnectionIndicators nai =
isupParameterFactory.createNatureOfConnectionIndicators();
- ForwardCallIndicators fci =
isupParameterFactory.createForwardCallIndicators();
- CallingPartyCategory cpg =
isupParameterFactory.createCallingPartyCategory();
- TransmissionMediumRequirement tmr =
isupParameterFactory.createTransmissionMediumRequirement();
- CalledPartyNumber cpn =
isupParameterFactory.createCalledPartyNumber();
- CallingPartyNumber cgp =
isupParameterFactory.createCallingPartyNumber();
- cpn.setAddress(bNumber);
- cgp.setAddress(aNumber);
- msg.setNatureOfConnectionIndicators(nai);
- msg.setForwardCallIndicators(fci);
- msg.setCallingPartCategory(cpg);
- msg.setCalledPartyNumber(cpn);
- msg.setCallingPartyNumber(cgp);
- msg.setTransmissionMediumRequirement(tmr);
- msg.setSls(this.getCicValue());
-
- try {
- CircuitActivity circuitActivity =
isupProvider.createCircuitActivity(msg,remoteSPC);
- ActivityContextInterface cicAci =
isupActivityContextInterfaceFactory.getActivityContextInterface(circuitActivity);
- cicAci.attach(sbbContext.getSbbLocalObject());
- circuitActivity.sendMessage(msg);
-
-// isupProvider.sendMessage(msg,remoteSPC);
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- try {
-
getSipEvent().getServerTransaction().sendResponse(response);
- } catch (InvalidArgumentException ex) {
- tracer.warning("InvalidArgumentException while trying to send
SESSION_PROGRESS Response (with sdp)", ex);
- } catch (SipException ex) {
- tracer.warning("SipException while trying to send SESSION_PROGRESS
Response (with sdp)", ex);
- }
- }
+
if(this.getConversionType().equals(Isup2SipPropertiesManagement.SIP_TO_ISUP))
+ onCreateConnectionResponseSipToIsup(event,aci);
+ else
if(this.getConversionType().equals(Isup2SipPropertiesManagement.ISUP_TO_SIP))
+ onCreateConnectionResponseIsupToSip(event,aci);
else {
- /* unable to create voice path (that's strange), so
- * mark CIC as IDLE
- * SIP: send SERVICE_UNAVAILABLE
-//!!!!!!! * detach MGCP
- */
- cicManagement.setIdle(this.getCicValue());
-
- try {
- Response response =
messageFactory.createResponse(Response.SERVER_INTERNAL_ERROR,
getSipEvent().getRequest());
-
getSipEvent().getServerTransaction().sendResponse(response);
- } catch (Exception ex) {
- tracer.warning("Exception while trying to send SERVER_INTERNAL_ERROR
Response", ex);
- }
+ tracer.severe("unexpected CRCX RESP");
}
}
@@ -364,6 +325,13 @@
+
+
+
+
+
+
+
@@ -458,6 +426,18 @@
public abstract String getMgcpConnectionIdentifier();
+ public abstract void setConversionType(String type);
+
+ public abstract String getConversionType();
+
+ public abstract void setANumber(String type);
+
+ public abstract String getANumber();
+
+ public abstract void setBNumber(String type);
+
+ public abstract String getBNumber();
+
public void setSbbContext(SbbContext context) {
this.sbbContext = context;
@@ -537,4 +517,211 @@
public void sbbRolledBack(RolledBackContext context) {
}
+ // depending on scenario, CRCX resp is processed in various ways
+ public void onCreateConnectionResponseSipToIsup(CreateConnectionResponse
event,
+ ActivityContextInterface aci) {
+ tracer.info("CRCX RESP (Sip->Isup) sbb=" +
sbbContext.getSbbLocalObject());
+
+ ReturnCode status = event.getReturnCode();
+
+ boolean connectionCreated = (status.getValue() ==
ReturnCode.TRANSACTION_EXECUTED_NORMALLY);
+ String sdp = null;
+
+ if(connectionCreated) {
+ sdp =
event.getLocalConnectionDescriptor().toString();
+ connectionCreated = (sdp!=null);
+ }
+ if(connectionCreated){
+ /* the following should be done:
+ * (1) SIP: send progress with sdp
+ * (2) ISUP: send IAM
+ */
+ ContentTypeHeader contentType = null;
+ try {
+ contentType =
headerFactory.createContentTypeHeader("application", "sdp");
+ } catch (ParseException ex) {}
+
+ Response response = null;
+ try {
+ response = messageFactory.createResponse(Response.SESSION_PROGRESS,
getSipEvent().getRequest(), contentType, sdp.getBytes());
+ } catch (ParseException ex) {
+ tracer.warning("ParseException while trying to create
SESSION_PROGRESS Response", ex);
+ }
+
+ // fetch A- and B- numbers
+ Request sipRequest =
this.getSipEvent().getRequest();
+ FromHeader fromHeader = (FromHeader)
sipRequest.getHeader(FromHeader.NAME);
+ ToHeader toHeader = (ToHeader)
sipRequest.getHeader(ToHeader.NAME);
+ final String aNumber =
CodingShemes.numberFromURI(fromHeader.getAddress().getURI().toString());
+ final String bNumber =
CodingShemes.numberFromURI(toHeader.getAddress().getURI().toString());
+ tracer.warning("To header=" + toHeader + "
->" + bNumber);
+ tracer.warning("From header=" + fromHeader + "
->" + aNumber);
+
+ InitialAddressMessage msg =
isupMessageFactory.createIAM(this.getCicValue());
+// CircuitIdentificationCode cic =
isupParameterFactory.createCircuitIdentificationCode();
+ NatureOfConnectionIndicators nai =
isupParameterFactory.createNatureOfConnectionIndicators();
+ ForwardCallIndicators fci =
isupParameterFactory.createForwardCallIndicators();
+ CallingPartyCategory cpg =
isupParameterFactory.createCallingPartyCategory();
+ TransmissionMediumRequirement tmr =
isupParameterFactory.createTransmissionMediumRequirement();
+ CalledPartyNumber cpn =
isupParameterFactory.createCalledPartyNumber();
+ CallingPartyNumber cgp =
isupParameterFactory.createCallingPartyNumber();
+ cpn.setAddress(bNumber);
+ cgp.setAddress(aNumber);
+ msg.setNatureOfConnectionIndicators(nai);
+ msg.setForwardCallIndicators(fci);
+ msg.setCallingPartCategory(cpg);
+ msg.setCalledPartyNumber(cpn);
+ msg.setCallingPartyNumber(cgp);
+ msg.setTransmissionMediumRequirement(tmr);
+ msg.setSls(this.getCicValue());
+
+ try {
+ CircuitActivity circuitActivity =
isupProvider.createCircuitActivity(msg,remoteSPC);
+ ActivityContextInterface cicAci =
isupActivityContextInterfaceFactory.getActivityContextInterface(circuitActivity);
+ cicAci.attach(sbbContext.getSbbLocalObject());
+ circuitActivity.sendMessage(msg);
+
+// isupProvider.sendMessage(msg,remoteSPC);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ try {
+
getSipEvent().getServerTransaction().sendResponse(response);
+ } catch (InvalidArgumentException ex) {
+ tracer.warning("InvalidArgumentException while trying to send
SESSION_PROGRESS Response (with sdp)", ex);
+ } catch (SipException ex) {
+ tracer.warning("SipException while trying to send SESSION_PROGRESS
Response (with sdp)", ex);
+ }
+ }
+ else {
+ /* unable to create voice path (that's
strange), so
+ * mark CIC as IDLE
+ * SIP: send SERVICE_UNAVAILABLE
+ //!!!!!!! * detach MGCP
+ */
+ cicManagement.setIdle(this.getCicValue());
+
+ try {
+ Response response =
messageFactory.createResponse(Response.SERVER_INTERNAL_ERROR,
getSipEvent().getRequest());
+
getSipEvent().getServerTransaction().sendResponse(response);
+ } catch (Exception ex) {
+ tracer.warning("Exception while trying to send SERVER_INTERNAL_ERROR
Response", ex);
+ }
+ }
+ }
+
+ public void onCreateConnectionResponseIsupToSip(CreateConnectionResponse
event,
+ ActivityContextInterface aci) {
+ tracer.info("CRCX RESP (Isup->Sip) sbb=" +
sbbContext.getSbbLocalObject());
+
+ ReturnCode status = event.getReturnCode();
+
+ boolean connectionCreated = (status.getValue() ==
ReturnCode.TRANSACTION_EXECUTED_NORMALLY);
+ String sdp = null;
+
+ if(connectionCreated) {
+ sdp =
event.getLocalConnectionDescriptor().toString();
+ connectionCreated = (sdp!=null);
+ }
+ if(connectionCreated){
+ /* the following should be done:
+ * (1?) ISUP: send ACM
+ * (2) SIP: send INVITE
+ */
+
+ AddressCompleteMessage msg =
isupMessageFactory.createACM(this.getCicValue());
+ BackwardCallIndicators bci =
isupParameterFactory.createBackwardCallIndicators();
+ msg.setBackwardCallIndicators(bci);
+ msg.setSls(this.getCicValue());
+ try {
+ // just to play with stack, send smth
+ isupProvider.sendMessage(msg,remoteSPC);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+
+ ContentTypeHeader contentType = null;
+ try {
+ contentType =
headerFactory.createContentTypeHeader("application", "sdp");
+ } catch (ParseException ex) {}
+
+ // just send SIP INVITE
+
+ try {
+ // create headers needed to create a
out-of-dialog request
+ AddressFactory addressFactory =
sipProvider.getAddressFactory();
+
+ Address fromNameAddress = addressFactory
+ .createAddress("sip:"+ this.getANumber() + "@" +
isup2SipPropertiesManagement.getSipIp());
+ Address toNameAddress = addressFactory
+ .createAddress("sip:"+ this.getBNumber() + "@" +
isup2SipPropertiesManagement.getSipPeer());
+
+ HeaderFactory headerFactory =
sipProvider.getHeaderFactory();
+ FromHeader fromHeader =
headerFactory.createFromHeader(
+ fromNameAddress, null);
+ ToHeader toHeader =
headerFactory.createToHeader(
+ toNameAddress, null);
+
+ CallIdHeader callIdHeader =
sipProvider.getNewCallId();
+
+ List<ViaHeader> viaHeaders = new
ArrayList<ViaHeader>(1);
+ ListeningPoint listeningPoint =
sipProvider.getListeningPoints()[0];
+ ViaHeader viaHeader =
sipProvider.getHeaderFactory()
+
.createViaHeader(listeningPoint.getIPAddress(),
+
listeningPoint.getPort(),
+
listeningPoint.getTransport(), null);
+ viaHeaders.add(viaHeader);
+ ContentTypeHeader contentTypeHeader =
headerFactory
+
.createContentTypeHeader("application", "sdp");
+ CSeqHeader cSeqHeader =
headerFactory.createCSeqHeader(2L,
+ Request.INVITE);
+ MaxForwardsHeader maxForwardsHeader =
headerFactory
+
.createMaxForwardsHeader(70);
+
+ // send a message to each contact of
the target resource
+ MessageFactory messageFactory =
sipProvider.getMessageFactory();
+
+ try {
+ // create request uri
+ tracer.warning("own SIP ip is " +
isup2SipPropertiesManagement.getSipIp() +
+ ", SIP peer
is " + isup2SipPropertiesManagement.getSipPeer());
+ URI requestURI =
addressFactory.createSipURI(this.getBNumber(),isup2SipPropertiesManagement.getSipPeer());
+ tracer.warning("sip uri is
"+requestURI);
+
+ Address contactAddress
= addressFactory
+
.createAddress("sip:" + isup2SipPropertiesManagement.getSipIp());
+ ContactHeader contactHeader =
headerFactory.createContactHeader(contactAddress);
+ tracer.warning("Contact is
"+ contactHeader);
+
+ // create request
+ Request invite =
messageFactory.createRequest(requestURI,
+
Request.INVITE,
+
callIdHeader,
+
cSeqHeader,
+
fromHeader,
+
toHeader, viaHeaders, maxForwardsHeader,
+
contentTypeHeader, sdp);
+
invite.setHeader(contactHeader);
+
+ // create client
transaction and send request
+ ClientTransaction
clientTransaction = sipProvider
+
.getNewClientTransaction(invite);
+
clientTransaction.sendRequest();
+ } catch (Throwable f) {
+ tracer.severe("Failed to
create and send message", f);
+ }
+
+ } catch (Throwable e) {
+ tracer.severe("Failed to create message
headers", e);
+ }
+
+
+ }
+ }
+
+
}
=======================================
--- /core/slee/sbbs/src/main/resources/META-INF/sbb-jar.xml Sat Aug 3
10:50:58 2013 UTC
+++ /core/slee/sbbs/src/main/resources/META-INF/sbb-jar.xml Fri Aug 16
18:40:11 2013 UTC
@@ -11,6 +11,9 @@
<sbb-abstract-class reentrant="True">
<sbb-abstract-class-name>org.mobicents.isup2sip.sbb.Isup2SipSbb</sbb-abstract-class-name>
<cmp-field>
+
<cmp-field-name>conversionType</cmp-field-name>
+ </cmp-field>
+ <cmp-field>
<cmp-field-name>sipEvent</cmp-field-name>
</cmp-field>
<cmp-field>
@@ -22,6 +25,12 @@
<cmp-field>
<cmp-field-name>mgcpConnectionIdentifier</cmp-field-name>
</cmp-field>
+ <cmp-field>
+ <cmp-field-name>aNumber</cmp-field-name>
+ </cmp-field>
+ <cmp-field>
+ <cmp-field-name>bNumber</cmp-field-name>
+ </cmp-field>
</sbb-abstract-class>
</sbb-classes>
==============================================================================
Revision: 80d406972ece
Author: dmisol <[email protected]>
Date: Mon Aug 19 18:23:33 2013 UTC
Log: still coding
http://code.google.com/p/isup2sip/source/detail?r=80d406972ece
Modified:
/core/slee/sbbs/src/main/java/org/mobicents/isup2sip/sbb/Isup2SipSbb.java
=======================================
---
/core/slee/sbbs/src/main/java/org/mobicents/isup2sip/sbb/Isup2SipSbb.java
Fri Aug 16 18:40:11 2013 UTC
+++
/core/slee/sbbs/src/main/java/org/mobicents/isup2sip/sbb/Isup2SipSbb.java
Mon Aug 19 18:23:33 2013 UTC
@@ -25,9 +25,14 @@
import jain.protocol.ip.mgcp.JainMgcpEvent;
import jain.protocol.ip.mgcp.message.CreateConnection;
import jain.protocol.ip.mgcp.message.CreateConnectionResponse;
+import jain.protocol.ip.mgcp.message.DeleteConnection;
+import jain.protocol.ip.mgcp.message.DeleteConnectionResponse;
+import jain.protocol.ip.mgcp.message.ModifyConnection;
+import jain.protocol.ip.mgcp.message.ModifyConnectionResponse;
import jain.protocol.ip.mgcp.message.parms.CallIdentifier;
import jain.protocol.ip.mgcp.message.parms.ConflictingParameterException;
import jain.protocol.ip.mgcp.message.parms.ConnectionDescriptor;
+import jain.protocol.ip.mgcp.message.parms.ConnectionIdentifier;
import jain.protocol.ip.mgcp.message.parms.ConnectionMode;
import jain.protocol.ip.mgcp.message.parms.EndpointIdentifier;
import jain.protocol.ip.mgcp.message.parms.ReturnCode;
@@ -95,6 +100,7 @@
import
org.mobicents.protocols.ss7.isup.message.parameter.CalledPartyNumber;
import
org.mobicents.protocols.ss7.isup.message.parameter.CallingPartyCategory;
import
org.mobicents.protocols.ss7.isup.message.parameter.CallingPartyNumber;
+import org.mobicents.protocols.ss7.isup.message.parameter.CauseIndicators;
import
org.mobicents.protocols.ss7.isup.message.parameter.CircuitIdentificationCode;
import
org.mobicents.protocols.ss7.isup.message.parameter.ForwardCallIndicators;
import
org.mobicents.protocols.ss7.isup.message.parameter.NatureOfConnectionIndicators;
@@ -172,36 +178,8 @@
String sdp = new
String(sipEvent.getRequest().getRawContent());
- CallIdentifier mgcpCallID =
mgcpProvider.getUniqueCallIdentifier();
- this.setMgcpCallIdentifier(mgcpCallID.toString());
- EndpointIdentifier endpointID = new
EndpointIdentifier(channel.getEndpointId(),channel.getGatewayAddress());
- CreateConnection createConnection = new
CreateConnection(this,
- mgcpCallID, endpointID,
ConnectionMode.SendRecv);
- try {
- createConnection.setRemoteConnectionDescriptor(new
ConnectionDescriptor(sdp));
- } catch (ConflictingParameterException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- final int txID =
mgcpProvider.getUniqueTransactionHandler();
- createConnection.setTransactionHandle(txID);
+ sendCRCX(sdp);
- MgcpConnectionActivity connectionActivity = null;
- try {
- connectionActivity = mgcpProvider.getConnectionActivity(txID,
endpointID);
- ActivityContextInterface epnAci =
mgcpActivityContestInterfaceFactory.getActivityContextInterface(connectionActivity);
- epnAci.attach(sbbLocalObject);
- } catch (FactoryException ex) {
- ex.printStackTrace();
- } catch (NullPointerException ex) {
- ex.printStackTrace();
- } catch (UnrecognizedActivityException ex) {
- ex.printStackTrace();
- }
-
- mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] {
createConnection });
- tracer.info("SIP->ISUP, CRCX sent; ep ID=" + endpointID + " sbb=" +
sbbLocalObject);
-
// with a proper CRCX_RESP, sent IAM..
} catch (Throwable e) {
@@ -234,30 +212,7 @@
tracer.warning("CIC is not idle");
}
- CallIdentifier mgcpCallID =
mgcpProvider.getUniqueCallIdentifier();
- this.setMgcpCallIdentifier(mgcpCallID.toString());
- EndpointIdentifier endpointID = new
EndpointIdentifier(channel.getEndpointId(),channel.getGatewayAddress());
- CreateConnection createConnection = new CreateConnection(this,
- mgcpCallID, endpointID,
ConnectionMode.SendRecv);
-
- final int txID = mgcpProvider.getUniqueTransactionHandler();
- createConnection.setTransactionHandle(txID);
-
- MgcpConnectionActivity connectionActivity = null;
- try {
- connectionActivity = mgcpProvider.getConnectionActivity(txID,
endpointID);
- ActivityContextInterface epnAci =
mgcpActivityContestInterfaceFactory.getActivityContextInterface(connectionActivity);
- epnAci.attach(sbbLocalObject);
- } catch (FactoryException ex) {
- ex.printStackTrace();
- } catch (NullPointerException ex) {
- ex.printStackTrace();
- } catch (UnrecognizedActivityException ex) {
- ex.printStackTrace();
- }
-
- mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] {
createConnection });
- tracer.info("ISUP->SIP, CRCX sent; ep ID=" + endpointID + " sbb=" +
sbbLocalObject);
+ sendCRCX(null);
}
@@ -285,8 +240,9 @@
tracer.warning("isup REL " +
rel.getCircuitIdentificationCode().getCIC());
showMe();
- ReleaseCompleteMessage msg =
isupMessageFactory.createRLC(this.getCicValue());
- msg.setSls(this.getCicValue());
+ final int cic = this.getCicValue();
+ ReleaseCompleteMessage msg = isupMessageFactory.createRLC(cic);
+ msg.setSls(cic);
try {
// just to play with stack, send smth
@@ -296,6 +252,7 @@
e.printStackTrace();
}
+ sendDLCX();
}
public void onRLC(ReleaseCompleteMessage rlc, ActivityContextInterface
aci){
@@ -317,10 +274,12 @@
}
}
- public void onModifyConnectionResponse(CreateConnectionResponse event,
- ActivityContextInterface aci) {}
+ public void onModifyConnectionResponse(ModifyConnectionResponse event,
+ ActivityContextInterface aci) {
+ tracer.warning("MDCX Resp, Isup->Sip ?");
+ }
- public void onDeleteConnectionResponse(CreateConnectionResponse event,
+ public void onDeleteConnectionResponse(DeleteConnectionResponse event,
ActivityContextInterface aci) {}
@@ -335,41 +294,63 @@
- public void onReInviteEvent(RequestEvent sipEvent,
ActivityContextInterface aci) {}
+ public void onReInviteEvent(RequestEvent sipEvent,
ActivityContextInterface aci) {
+ String sdp = new String(sipEvent.getRequest().getRawContent());
+ if( ! sdp.isEmpty()){
+ sendMDCX(sdp);
+ }
+
+ sipReplyToRequestEvent(sipEvent, Response.OK);
+
+ }
// Responses
- public void on1xxResponse(ResponseEvent event, ActivityContextInterface
aci) {
- if (event.getResponse().getStatusCode() == Response.TRYING) {
- // those are not forwarded to the other dialog
- return;
+ public void on1xxResponse(ResponseEvent sipEvent,
ActivityContextInterface aci) {
+ tracer.severe("on1xxResp: " + sipEvent);
+ String sdp = new String(sipEvent.getResponse().getRawContent());
+ if( sdp != null){
+ sendMDCX(sdp);
}
- processResponse(event, aci);
}
- public void on2xxResponse(ResponseEvent event, ActivityContextInterface
aci) {
- final CSeqHeader cseq = (CSeqHeader)
event.getResponse().getHeader(
+ public void on2xxResponse(ResponseEvent sipEvent,
ActivityContextInterface aci) {
+ tracer.severe("on2xxResp:" + sipEvent);
+ final CSeqHeader cseq = (CSeqHeader)
sipEvent.getResponse().getHeader(
CSeqHeader.NAME);
if (cseq.getMethod().equals(Request.INVITE)) {
// lets ack it ourselves to avoid UAS retransmissions
due to
// forwarding of this response and further UAC Ack
// note that the app does not handles UAC ACKs
try {
- final Request ack = event.getDialog().createAck(
+ final Request ack =
sipEvent.getDialog().createAck(
cseq.getSeqNumber());
- event.getDialog().sendAck(ack);
+ sipEvent.getDialog().sendAck(ack);
} catch (Exception e) {
tracer.severe("Unable to ack INVITE's 200 ok from
UAS", e);
}
} else if (cseq.getMethod().equals(Request.BYE)
|| cseq.getMethod().equals(Request.CANCEL)) {
- // not forwarded to the other dialog
return;
}
- processResponse(event, aci);
}
public void onBye(RequestEvent event, ActivityContextInterface aci) {
+ final int cic = this.getCicValue();
+ ReleaseMessage msg = isupMessageFactory.createREL(cic);
+ msg.setSls(cic);
+ CauseIndicators cause =
isupParameterFactory.createCauseIndicators();
+ cause.setCauseValue(CauseIndicators._CV_ALL_CLEAR);
+ msg.setCauseIndicators(cause);
+ try {
+ // just to play with stack, send smth
+ isupProvider.sendMessage(msg,remoteSPC);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ sendDLCX();
}
public void onCancel(CancelRequestEvent event, ActivityContextInterface
aci) {
@@ -397,14 +378,6 @@
}
}
- private void processResponse(ResponseEvent event,
- ActivityContextInterface aci) {
- try {
-
- } catch (Exception e) {
- tracer.severe(e.getMessage(), e);
- }
- }
@@ -652,7 +625,7 @@
// just send SIP INVITE
try {
- // create headers needed to create a
out-of-dialog request
+ // create headers needed
AddressFactory addressFactory =
sipProvider.getAddressFactory();
Address fromNameAddress = addressFactory
@@ -685,6 +658,10 @@
// send a message to each contact of
the target resource
MessageFactory messageFactory =
sipProvider.getMessageFactory();
+
+
+
+
try {
// create request uri
tracer.warning("own SIP ip is " +
isup2SipPropertiesManagement.getSipIp() +
@@ -706,10 +683,16 @@
toHeader, viaHeaders, maxForwardsHeader,
contentTypeHeader, sdp);
invite.setHeader(contactHeader);
-
+
// create client
transaction and send request
ClientTransaction
clientTransaction = sipProvider
.getNewClientTransaction(invite);
+
+ final DialogActivity sipDialog = (DialogActivity)
sipProvider.getNewDialog(clientTransaction);
+ final ActivityContextInterface sipDialogACI =
sipActivityContextInterfaceFactory.getActivityContextInterface(sipDialog);
+ final SbbLocalObject sbbLocalObject =
sbbContext.getSbbLocalObject();
+
sipDialogACI.attach(sbbLocalObject);
+
clientTransaction.sendRequest();
} catch (Throwable f) {
tracer.severe("Failed to
create and send message", f);
@@ -723,5 +706,106 @@
}
}
+ void sendCRCX(String sdp){
+
+ final SbbLocalObject sbbLocalObject =
sbbContext.getSbbLocalObject();
+ final int cic = this.getCicValue();
+ final Channel channel = cicManagement.getChannelByCic(cic);
+
+ CallIdentifier mgcpCallID =
mgcpProvider.getUniqueCallIdentifier();
+ this.setMgcpCallIdentifier(mgcpCallID.toString());
+ EndpointIdentifier endpointID = new
EndpointIdentifier(channel.getEndpointId(),channel.getGatewayAddress());
+ CreateConnection createConnection = new CreateConnection(this,
+ mgcpCallID, endpointID,
ConnectionMode.SendRecv);
+ if(sdp !=null)
+ try {
+ createConnection.setRemoteConnectionDescriptor(new
ConnectionDescriptor(sdp));
+ } catch (ConflictingParameterException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ final int txID = mgcpProvider.getUniqueTransactionHandler();
+ createConnection.setTransactionHandle(txID);
+
+ MgcpConnectionActivity connectionActivity = null;
+ try {
+ connectionActivity = mgcpProvider.getConnectionActivity(txID,
endpointID);
+ ActivityContextInterface epnAci =
mgcpActivityContestInterfaceFactory.getActivityContextInterface(connectionActivity);
+ epnAci.attach(sbbLocalObject);
+ } catch (FactoryException ex) {
+ ex.printStackTrace();
+ } catch (NullPointerException ex) {
+ ex.printStackTrace();
+ } catch (UnrecognizedActivityException ex) {
+ ex.printStackTrace();
+ }
+
+ mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] {
createConnection });
+ tracer.info("CRCX sent; ep ID=" + endpointID + " sbb=" +
sbbLocalObject);
+ }
+ void sendMDCX(String sdp){
+
+ final SbbLocalObject sbbLocalObject =
sbbContext.getSbbLocalObject();
+ final int cic = this.getCicValue();
+ final Channel channel = cicManagement.getChannelByCic(cic);
+ CallIdentifier mgcpCallID = new
CallIdentifier(this.getMgcpCallIdentifier());
+ this.setMgcpCallIdentifier(mgcpCallID.toString());
+ EndpointIdentifier endpointID = new
EndpointIdentifier(channel.getEndpointId(),channel.getGatewayAddress());
+ ConnectionIdentifier connectionIdentifier = new
ConnectionIdentifier(this.getMgcpConnectionIdentifier());
+ ModifyConnection modifyConnection = new ModifyConnection(this,
mgcpCallID, endpointID,connectionIdentifier);
+ try {
+ modifyConnection.setRemoteConnectionDescriptor(new
ConnectionDescriptor(sdp));
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ final int txID = mgcpProvider.getUniqueTransactionHandler();
+ modifyConnection.setTransactionHandle(txID);
+
+ MgcpConnectionActivity connectionActivity = null;
+ try {
+ connectionActivity = mgcpProvider.getConnectionActivity(txID,
endpointID);
+ ActivityContextInterface epnAci =
mgcpActivityContestInterfaceFactory.getActivityContextInterface(connectionActivity);
+ epnAci.attach(sbbLocalObject);
+ } catch (FactoryException ex) {
+ ex.printStackTrace();
+ } catch (NullPointerException ex) {
+ ex.printStackTrace();
+ } catch (UnrecognizedActivityException ex) {
+ ex.printStackTrace();
+ }
+
+ mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] {
modifyConnection });
+ tracer.info("DLCX sent; ep ID=" + endpointID + " sbb=" +
sbbLocalObject);
+
+ }
+
+ void sendDLCX(){
+
+ final SbbLocalObject sbbLocalObject =
sbbContext.getSbbLocalObject();
+ final Channel channel =
cicManagement.getChannelByCic(this.getCicValue());
+ CallIdentifier mgcpCallID = new
CallIdentifier(this.getMgcpCallIdentifier());
+ EndpointIdentifier endpointID = new
EndpointIdentifier(channel.getEndpointId(),channel.getGatewayAddress());
+ DeleteConnection deleteConnection = new DeleteConnection(this,
mgcpCallID, endpointID);
+ final int txID = mgcpProvider.getUniqueTransactionHandler();
+ deleteConnection.setTransactionHandle(txID);
+
+ MgcpConnectionActivity connectionActivity = null;
+ try {
+ connectionActivity = mgcpProvider.getConnectionActivity(txID,
endpointID);
+ ActivityContextInterface epnAci =
mgcpActivityContestInterfaceFactory.getActivityContextInterface(connectionActivity);
+ epnAci.attach(sbbLocalObject);
+ } catch (FactoryException ex) {
+ ex.printStackTrace();
+ } catch (NullPointerException ex) {
+ ex.printStackTrace();
+ } catch (UnrecognizedActivityException ex) {
+ ex.printStackTrace();
+ }
+
+ mgcpProvider.sendMgcpEvents(new JainMgcpEvent[] {
deleteConnection });
+ tracer.info("DLCX sent; ep ID=" + endpointID + " sbb=" +
sbbLocalObject);
+
+ }
}
--
---
You received this message because you are subscribed to the Google Groups "mobicents-commits" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.