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

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

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

import org.restcomm.protocols.ss7.sccp.SccpConnection;
import org.restcomm.protocols.ss7.sccp.SccpConnectionState;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnAkMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnCcMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnDt2MessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnItMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnRsrMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.message.SccpConnSegmentableMessageImpl;
import org.restcomm.protocols.ss7.sccp.impl.parameter.CreditImpl;
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.LocalReference;
import org.restcomm.protocols.ss7.sccp.parameter.ProtocolClass;
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.CR_RECEIVED;
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;

public class SccpConnectionWithFlowControlImpl extends SccpConnectionImpl implements SccpConnection {

    protected SccpFlowControl flow;

    private boolean overloaded;

    public SccpConnectionWithFlowControlImpl(int localSsn, LocalReference localReference, ProtocolClass protocol, SccpStackImpl stack, SccpRoutingControl sccpRoutingControl) {
        super(localSsn, localReference, protocol, stack, sccpRoutingControl);
        if (protocol.getProtocolClass() != 3) {
            logger.error("Using connection class for non-supported protocol class 2");
            throw new IllegalArgumentException();
        }
    }

    public void establish(SccpConnCrMessage message) throws IOException {
        this.flow = newSccpFlowControl(message.getCredit());
        super.establish(message);
    }

    public void confirm(SccpAddress respondingAddress, Credit credit, byte[] data) throws Exception {
        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()));
        }
        this.flow = newSccpFlowControl(credit);

        super.confirm(respondingAddress, credit, data);
    }

    protected SccpFlowControl newSccpFlowControl(Credit credit) {
        return new SccpFlowControl(stack.name, credit.getValue());
    }

    public void setOverloaded(boolean overloaded) throws Exception {
        try {
            connectionLock.lock();

            if (this.overloaded == overloaded) {
                return;
            }
            if (overloaded) {
                sendAk(new CreditImpl(0));
            } else {
                sendAk();
            }
            this.overloaded = overloaded;

        } finally {
            connectionLock.unlock();
        }
    }

    public void prepareMessageForSending(SccpConnSegmentableMessageImpl message) {
        if (message instanceof SccpConnDt2MessageImpl) {
            SccpConnDt2MessageImpl dt2 = (SccpConnDt2MessageImpl) message;

            flow.initializeMessageNumbering(dt2);
            flow.checkOutputMessageNumbering(dt2);

            if (!flow.isAuthorizedToTransmitAnotherMessage()) {
                setState(ESTABLISHED_SEND_WINDOW_EXHAUSTED);
            }

        } else {
            throw new IllegalArgumentException();
        }
    }

    protected void prepareMessageForSending(SccpConnItMessageImpl it) {
        it.setCredit(new CreditImpl(flow.getReceiveCredit()));

        flow.initializeMessageNumbering(it);
        flow.checkOutputMessageNumbering(it);

        if (!flow.isAuthorizedToTransmitAnotherMessage()) {
            setState(ESTABLISHED_SEND_WINDOW_EXHAUSTED);
        }
    }

    public void receiveMessage(SccpConnMessage message) throws Exception {
        try {
            connectionLock.lock();
            super.receiveMessage(message);

            if (message instanceof SccpConnCcMessageImpl) {
                SccpConnCcMessageImpl cc = (SccpConnCcMessageImpl) message;
                if (cc.getCredit() != null) {
                    this.flow = newSccpFlowControl(cc.getCredit());
                }

            } else if (message instanceof SccpConnAkMessageImpl) {
                handleAkMessage((SccpConnAkMessageImpl) message);
            } else if (message instanceof SccpConnRsrMessageImpl) {
                flow.reinitialize();
            }
        } finally {
            connectionLock.unlock();
        }
    }

    protected void receiveDataMessage(SccpConnSegmentableMessageImpl msg) throws Exception {
        if (!isAvailable()) {
            logger.error(getState() + " Message discarded " + msg);
            return;
        }
        if (!(msg instanceof SccpConnDt2MessageImpl)) {
            logger.error("Using protocol class 3, DT1 message discarded " + msg);
            return;
        }

        SccpConnDt2MessageImpl dt2 = (SccpConnDt2MessageImpl) msg;

        boolean correctNumbering = flow.checkInputMessageNumbering(this, dt2.getSequencingSegmenting().getSendSequenceNumber(),
                dt2.getSequencingSegmenting().getReceiveSequenceNumber());

        if (flow.isAkSendCriterion(dt2)) {
            sendAk();
        }
        if (correctNumbering) {
            super.receiveDataMessage(msg);
        } else {
            logger.error(String.format("Message %s was discarded due to incorrect sequence numbers", msg.toString()));
        }

        if (flow.isAuthorizedToTransmitAnotherMessage()) {
            setState(ESTABLISHED);
        } else {
            setState(ESTABLISHED_SEND_WINDOW_EXHAUSTED);
        }
    }

    protected void sendAk() throws Exception {
        sendAk(new CreditImpl(flow.getMaximumWindowSize()));
    }

    protected void sendAk(Credit credit) throws Exception {
        SccpConnAkMessageImpl msg = new SccpConnAkMessageImpl(0, 0);
        msg.setDestinationLocalReferenceNumber(getRemoteReference());
        msg.setSourceLocalReferenceNumber(getLocalReference());
        msg.setCredit(credit);

        flow.setReceiveCredit(credit.getValue());
        flow.initializeMessageNumbering(msg);

        sendMessage(msg);
    }

    private void handleAkMessage(SccpConnAkMessageImpl msg) throws Exception {


        flow.checkInputMessageNumbering(this, msg.getReceiveSequenceNumber().getNumber());
        flow.setSendCredit(msg.getCredit().getValue());

        if (flow.isAuthorizedToTransmitAnotherMessage()) {
            setState(ESTABLISHED);
        } else {
            setState(ESTABLISHED_SEND_WINDOW_EXHAUSTED);
        }
    }

    public void reset(ResetCause reason) throws Exception {
        super.reset(reason);
        flow.reinitialize();
    }

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

    protected boolean isCanSendData() {
        try {
            connectionLock.lock();

            SccpConnectionState oldState = getState();
            if (oldState == ESTABLISHED_SEND_WINDOW_EXHAUSTED && flow.isAuthorizedToTransmitAnotherMessage()) {
                setState(ESTABLISHED);
            }
            return getState() == ESTABLISHED;

        } finally {
            connectionLock.unlock();
        }
    }

    public Credit getSendCredit() {
        return new CreditImpl(flow.getSendCredit());
    }

    public Credit getReceiveCredit() {
        return new CreditImpl(flow.getReceiveCredit());
    }

    protected boolean isPreemptiveAck() {
        return flow.isPreemptiveAk();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();

        sb.append("ConnectionWithFlowControl[");

        fillSccpConnectionFields(sb);
        if (overloaded)
            sb.append(", overloaded");
        sb.append("]");

        return sb.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy