All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.restcomm.protocols.ss7.sccp.impl.SccpConnectionBaseImpl Maven / Gradle / Ivy

The newest version!
package org.restcomm.protocols.ss7.sccp.impl;

import org.apache.log4j.Logger;
import org.restcomm.protocols.ss7.sccp.SccpConnectionState;
import org.restcomm.protocols.ss7.sccp.SccpListener;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnCcMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnCrMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnCrefMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnErrMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnItMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnRlcMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnRlsdMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnRscMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnRsrMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnSegmentableMessageImpl;
import org.restcomm.protocols.ss7.sccp.message.SccpConnCrMessage;
import org.restcomm.protocols.ss7.sccp.message.SccpConnMessage;
import org.restcomm.protocols.ss7.sccp.parameter.Credit;
import org.restcomm.protocols.ss7.sccp.parameter.ErrorCause;
import org.restcomm.protocols.ss7.sccp.parameter.LocalReference;
import org.restcomm.protocols.ss7.sccp.parameter.ProtocolClass;
import org.restcomm.protocols.ss7.sccp.parameter.RefusalCause;
import org.restcomm.protocols.ss7.sccp.parameter.ReleaseCause;
import org.restcomm.protocols.ss7.sccp.parameter.ResetCause;
import org.restcomm.protocols.ss7.sccp.parameter.SccpAddress;

import java.io.IOException;
import java.util.concurrent.locks.ReentrantLock;

import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.CLOSED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.CONNECTION_INITIATED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.CR_RECEIVED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.DISCONNECT_INITIATED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.ESTABLISHED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.ESTABLISHED_SEND_WINDOW_EXHAUSTED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.NEW;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.RSR_PROPAGATED_VIA_COUPLED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.RSR_RECEIVED;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.RSR_RECEIVED_WILL_PROPAGATE;
import static org.restcomm.protocols.ss7.sccp.SccpConnectionState.RSR_SENT;

public abstract class SccpConnectionBaseImpl {

    protected final Logger logger;
    protected SccpStackImpl stack;
    protected SccpRoutingControl sccpRoutingControl;
    protected ReentrantLock connectionLock = new ReentrantLock();
    protected Integer remoteSsn;
    protected Integer remoteDpc;
    protected boolean lastMoreDataSent;

    private SccpConnectionState state;
    private int sls;
    private int localSsn;
    private ProtocolClass protocolClass;
    private LocalReference localReference;
    private LocalReference remoteReference;

    public SccpConnectionBaseImpl(int sls, int localSsn, LocalReference localReference, ProtocolClass protocol, SccpStackImpl stack, SccpRoutingControl sccpRoutingControl) {
        this.stack = stack;
        this.sccpRoutingControl = sccpRoutingControl;
        this.sls = sls;
        this.localSsn = localSsn;
        this.protocolClass = protocol;
        this.localReference = localReference;
        this.state = NEW;
        this.logger = Logger.getLogger(SccpConnectionBaseImpl.class.getCanonicalName() + "-" + localReference + "-" + stack.name);
    }

    protected void receiveMessage(SccpConnMessage message) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Rx : SCCP message %s", message.toString()));
        }

        if (message instanceof SccpConnCrMessageImpl) {
            SccpConnCrMessageImpl cr = (SccpConnCrMessageImpl) message;
            remoteReference = cr.getSourceLocalReferenceNumber();
            if (cr.getCallingPartyAddress() != null && cr.getCallingPartyAddress().getSignalingPointCode() != 0) {
                remoteDpc = cr.getCallingPartyAddress().getSignalingPointCode();
            } else {
                if (cr.getIncomingOpc() != -1) {
                    remoteDpc = cr.getIncomingOpc();
                } else {
                    // when both users are on the same stack
                    remoteDpc = cr.getCalledPartyAddress().getSignalingPointCode();
                }
            }
            setState(CR_RECEIVED);

        } else if (message instanceof SccpConnCcMessageImpl) {
            SccpConnCcMessageImpl cc = (SccpConnCcMessageImpl) message;
            remoteReference = cc.getSourceLocalReferenceNumber();
            if (cc.getIncomingDpc() != -1) {
                remoteDpc = cc.getIncomingOpc();
            }
            setState(SccpConnectionState.ESTABLISHED);

        } else if (message instanceof SccpConnRscMessageImpl) {
            setState(SccpConnectionState.ESTABLISHED);

        } else if (message instanceof SccpConnRsrMessageImpl) {
            confirmReset();
        } else if (message instanceof SccpConnRlsdMessageImpl) {
            confirmRelease();
        }
    }

    protected void confirmRelease() throws Exception {
        SccpConnRlcMessageImpl rlc = new SccpConnRlcMessageImpl(sls, localSsn);
        rlc.setSourceLocalReferenceNumber(localReference);
        rlc.setDestinationLocalReferenceNumber(remoteReference);
        rlc.setOutgoingDpc(remoteDpc);
        sendMessage(rlc);
    }

    protected void confirmReset() throws Exception {
        setState(RSR_RECEIVED);

        SccpConnRscMessageImpl rsc = new SccpConnRscMessageImpl(sls, localSsn);
        rsc.setDestinationLocalReferenceNumber(remoteReference);
        rsc.setSourceLocalReferenceNumber(localReference);
        sendMessage(rsc);

        setState(SccpConnectionState.ESTABLISHED);
    }

    protected void sendErr(ErrorCause cause) throws Exception {
        SccpConnErrMessageImpl err = new SccpConnErrMessageImpl(sls, localSsn);
        err.setDestinationLocalReferenceNumber(remoteReference);
        err.setSourceLocalReferenceNumber(localReference);
        err.setErrorCause(cause);

        sendMessage(err);
    }

    protected void sendMessage(SccpConnMessage message) throws Exception {
        if (message instanceof SccpConnSegmentableMessageImpl) { // data message
            prepareMessageForSending((SccpConnSegmentableMessageImpl) message);
        }
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Tx : SCCP Message=%s", message.toString()));
        }
        try {
            this.sccpRoutingControl.routeMssgFromSccpUserConn(message);
        } catch (Exception e) {
            // log here Exceptions from MTP3 level
            logger.error("IOException when sending the message to MTP3 level: " + e.getMessage(), e);
            throw e;
        }
    }

    public void setState(SccpConnectionState state) {
        try {
            connectionLock.lock();
            if (!(this.state == NEW && state == CONNECTION_INITIATED
                    || this.state == NEW && state == CR_RECEIVED
                    || this.state == NEW && state == CLOSED
                    || this.state == CR_RECEIVED && state == ESTABLISHED
                    || this.state == CR_RECEIVED && state == CLOSED
                    || this.state == CONNECTION_INITIATED && state == ESTABLISHED
                    || this.state == CONNECTION_INITIATED && state == CLOSED
                    || this.state == ESTABLISHED && state == ESTABLISHED
                    || this.state == ESTABLISHED && state == CLOSED
                    || this.state == ESTABLISHED && state == RSR_SENT
                    || this.state == ESTABLISHED && state == RSR_RECEIVED
                    || this.state == ESTABLISHED && state == ESTABLISHED_SEND_WINDOW_EXHAUSTED
                    || this.state == ESTABLISHED && state == RSR_RECEIVED_WILL_PROPAGATE
                    || this.state == ESTABLISHED && state == DISCONNECT_INITIATED
                    || this.state == DISCONNECT_INITIATED && state == DISCONNECT_INITIATED // repeated RLSD
                    || this.state == DISCONNECT_INITIATED && state == CLOSED
                    || this.state == ESTABLISHED_SEND_WINDOW_EXHAUSTED && state == ESTABLISHED
                    || this.state == ESTABLISHED_SEND_WINDOW_EXHAUSTED && state == ESTABLISHED_SEND_WINDOW_EXHAUSTED
                    || this.state == ESTABLISHED_SEND_WINDOW_EXHAUSTED && state == RSR_RECEIVED
                    || this.state == ESTABLISHED_SEND_WINDOW_EXHAUSTED && state == CLOSED
                    || this.state == ESTABLISHED_SEND_WINDOW_EXHAUSTED && state == DISCONNECT_INITIATED
                    || this.state == RSR_SENT && state == ESTABLISHED
                    || this.state == RSR_SENT && state == CLOSED
                    || this.state == RSR_RECEIVED && state == ESTABLISHED
                    || this.state == RSR_RECEIVED_WILL_PROPAGATE && state == RSR_PROPAGATED_VIA_COUPLED
                    || this.state == RSR_PROPAGATED_VIA_COUPLED && state == ESTABLISHED
                    || this.state == RSR_RECEIVED && state == CLOSED
                    // when error happens during message routing connection becomes immediately closed
                    || this.state == CLOSED && state == CLOSED
            )) {
                logger.error(String.format("state change error: from %s to %s", this.state, state));
                throw new IllegalStateException(String.format("state change error: from %s to %s", this.state, state));
            }
            this.state = state;
        } finally {
            connectionLock.unlock();
        }
    }

    protected void checkLocalListener() throws IOException {
        if (stack.sccpProvider.getSccpListener(getLocalSsn()) == null) {

            logger.error(String.format("Attempting to establish connection but the SSN %d is not available", getLocalSsn()));
            throw new IOException(String.format(
                    "Attempting to establish connection but the SSN %d is not available", getLocalSsn()));
        }
    }

    public void establish(SccpConnCrMessage message) throws IOException {
        checkLocalListener();
        try {
            message.setSourceLocalReferenceNumber(getLocalReference());

            if (message.getCalledPartyAddress() == null) {
                logger.error("Message to send must have filled CalledPartyAddress field");
                throw new IOException("Message to send must have filled CalledPartyAddress field");
            }
            setState(CONNECTION_INITIATED);
            remoteSsn = message.getCalledPartyAddress().getSubsystemNumber();
            if (message.getCalledPartyAddress().getAddressIndicator().isPCPresent()) {
                remoteDpc = (message.getCalledPartyAddress().getSignalingPointCode());
            }

            if (logger.isDebugEnabled()) {
                logger.debug(String.format("Establishing connection to DPC=%d, SSN=%d", getRemoteDpc(), getRemoteSsn()));
            }

            sendMessage(message);

        } catch (Exception e) {
            logger.error(e);
            throw new IOException(e);
        }
    }

    public void reset(ResetCause reason) throws Exception {
        if (reason.getValue().isError()) {
            logger.warn(String.format("Resetting connection to DPC=%d, SSN=%d, DLR=%s due to %s", getRemoteDpc(), getRemoteSsn(),
                    getRemoteReference(), reason));

        } else if (logger.isDebugEnabled()) {
            logger.debug(String.format("Resetting connection to DPC=%d, SSN=%d, DLR=%s due to %s", getRemoteDpc(), getRemoteSsn(),
                    getRemoteReference(), reason));
        }
        SccpConnRsrMessageImpl rsr = new SccpConnRsrMessageImpl(getSls(), getLocalSsn());
        rsr.setSourceLocalReferenceNumber(getLocalReference());
        rsr.setDestinationLocalReferenceNumber(getRemoteReference());
        rsr.setResetCause(reason);
        setState(RSR_SENT);
        sendMessage(rsr);
    }

    public void resetSection(ResetCause reason) throws Exception {
        reset(reason);
    }

    public void disconnect(ReleaseCause reason, byte[] data) throws Exception {
        if (reason.getValue().isError()) {
            logger.warn(String.format("Disconnecting connection to DPC=%d, SSN=%d, DLR=%s due to %s", getRemoteDpc(),
                    getRemoteSsn(), getRemoteReference(), reason));
        } else if (logger.isDebugEnabled()) {
            logger.debug(String.format("Disconnecting connection to DPC=%d, SSN=%d, DLR=%s due to %s", getRemoteDpc(),
                    getRemoteSsn(), getRemoteReference(), reason));
        }

        SccpConnRlsdMessageImpl rlsd = new SccpConnRlsdMessageImpl(getSls(), getLocalSsn());
        rlsd.setDestinationLocalReferenceNumber(getRemoteReference());
        rlsd.setReleaseCause(reason);
        rlsd.setSourceLocalReferenceNumber(getLocalReference());
        rlsd.setUserData(data);
        SccpConnectionState prevState = state;
        try {
            setState(DISCONNECT_INITIATED);
            sendMessage(rlsd);
        } catch (Exception e) {
            state = prevState;
            throw e;
        }
    }

    public void refuse(RefusalCause reason, byte[] data) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Refusing connection from DPC=%d, SSN=%d, DLR=%s due to %s", getRemoteDpc(),
                    getRemoteSsn(), getRemoteReference(), reason));
        }
        SccpConnCrefMessageImpl cref = new SccpConnCrefMessageImpl(getSls(), getLocalSsn());
        cref.setDestinationLocalReferenceNumber(getRemoteReference());
        cref.setSourceLocalReferenceNumber(getLocalReference());
        cref.setRefusalCause(reason);
        cref.setUserData(data);
        sendMessage(cref);
        stack.removeConnection(getLocalReference());
    }

    public void confirm(SccpAddress respondingAddress, Credit credit, byte[] data) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Confirming connection from DPC=%d, SSN=%d, DLR=%s", getRemoteDpc(),
                    getRemoteSsn(), getRemoteReference()));
        }
        if (getState() != CR_RECEIVED) {
            logger.error(String.format("Trying to confirm connection in non-compatible state %s", getState()));
            throw new IllegalStateException(String.format("Trying to confirm connection in non-compatible state %s", getState()));
        }
        SccpConnCcMessageImpl message = new SccpConnCcMessageImpl(getSls(), getLocalSsn());
        message.setSourceLocalReferenceNumber(getLocalReference());
        message.setDestinationLocalReferenceNumber(getRemoteReference());
        message.setProtocolClass(getProtocolClass());
        message.setCalledPartyAddress(respondingAddress);
        message.setUserData(data);
        message.setCredit(credit);

        sendMessage(message);

        setState(SccpConnectionState.ESTABLISHED);
    }

    protected void setConnectionLock(ReentrantLock lock) {
        if (getState() != NEW) {
            throw new IllegalStateException();
        }
        this.connectionLock = lock;
    }

    public Integer getRemoteDpc() {
        return remoteDpc;
    }

    public Integer getRemoteSsn() {
        // could be unknown i. e. null
        return remoteSsn;
    }

    public void setRemoteSsn(Integer val) {
        remoteSsn = val;
    }

    public SccpListener getListener() {
        return stack.sccpProvider.getSccpListener(localSsn);
    }

    public int getSls() {
        return sls;
    }

    public int getLocalSsn() {
        return localSsn;
    }

    public LocalReference getLocalReference() {
        return localReference;
    }

    public LocalReference getRemoteReference() {
        return remoteReference;
    }

    public SccpConnectionState getState() {
        return state;
    }

    public ProtocolClass getProtocolClass() {
        return protocolClass;
    }

    public boolean isAvailable() {
        return state == ESTABLISHED || state == ESTABLISHED_SEND_WINDOW_EXHAUSTED;
    }

    protected boolean isCanSendData() {
        return state == ESTABLISHED;
    }

    public Credit getSendCredit() {
        throw new IllegalArgumentException("sendCredit is supported only by flow control connection-oriented protocol class");
    }

    public Credit getReceiveCredit() {
        throw new IllegalArgumentException("receiveCredit is supported only by flow control connection-oriented protocol class");
    }

    public abstract void prepareMessageForSending(SccpConnSegmentableMessageImpl message);
    protected abstract void prepareMessageForSending(SccpConnItMessageImpl message);
    protected abstract void callListenerOnData(byte[] data);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy