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

io.snice.networking.examples.gtp.Sgw2 Maven / Gradle / Ivy

package io.snice.networking.examples.gtp;


import io.hektor.core.Hektor;
import io.snice.buffer.Buffer;
import io.snice.buffer.Buffers;
import io.snice.codecs.codec.MccMnc;
import io.snice.codecs.codec.gtp.Teid;
import io.snice.codecs.codec.gtp.gtpc.v1.Gtp1Message;
import io.snice.codecs.codec.gtp.gtpc.v2.Gtp2Message;
import io.snice.codecs.codec.gtp.gtpc.v2.messages.tunnel.CreateSessionRequest;
import io.snice.codecs.codec.gtp.gtpc.v2.tliv.Uli;
import io.snice.codecs.codec.gtp.gtpc.v2.type.EcgiField;
import io.snice.codecs.codec.gtp.gtpc.v2.type.RatType;
import io.snice.codecs.codec.gtp.gtpc.v2.type.TaiField;
import io.snice.codecs.codec.gtp.gtpc.v2.type.UliType;
import io.snice.codecs.codec.internet.IpMessage;
import io.snice.codecs.codec.internet.ipv4.IPv4Message;
import io.snice.codecs.codec.transport.UdpMessage;
import io.snice.networking.gtp.*;
import io.snice.networking.gtp.event.GtpEvent;

import java.util.concurrent.atomic.AtomicReference;

import static io.snice.codecs.codec.gtp.gtpc.v2.type.PdnType.Type.IPv4;

/**
 * Sample app that ties together both GTP-C and GTP-U
 */
public class Sgw2 extends GtpApplication {

    /**
     * Our one and only tunnel, which of course in a real application is un-realistic but for
     * this simple example, we don't care. We'll establish exactly one tunnel and use it for
     * everything.
     */
    private final AtomicReference tunnel = new AtomicReference<>();
    private GtpEnvironment environment;
    private Hektor hektor;

    /**
     * dns query for google.com. Grabbed from wireshark
     */
    public final static Buffer dnsQuery = Buffer.of(
            (byte) 0x5c, (byte) 0x79, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x77, (byte) 0x77, (byte) 0x77,
            (byte) 0x06, (byte) 0x67, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x03,
            (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01);

    @Override
    public void initialize(final GtpBootstrap bootstrap) {
        bootstrap.onConnection(c -> true).accept(b -> {
            b.match(GtpEvent::isPdu).map(GtpEvent::toGtp1Message).consume(Sgw2::processPdu);
            b.match(GtpEvent::isCreateSessionResponse).map(GtpEvent::toGtp2Message).consume(Sgw2::processCreateSessionResponse);
            b.match(GtpEvent::isDeleteSessionResponse).map(GtpEvent::toGtp2Message).consume(Sgw2::processDeleteSessionResponse);
        });

    }

    private static void processPdu(final GtpTunnel tunnel, final Gtp1Message pdu) {

        // TODO: some convenience methods for dealing with IP packets would be nice...
        final var payload = pdu.getPayload().get();
        final IPv4Message ipv4 = IpMessage.frame(payload).toIPv4();
        final var udp = UdpMessage.frame(ipv4.getPayload());
        final var content = udp.getPayload();

        // now do something with the content.
    }

    private static void processCreateSessionResponse(final GtpTunnel tunnel, final Gtp2Message message) {
        // actually, now with Transaction support, we don't "go" this way anymore...
        final var response = message.toGtp2Message().toCreateSessionRequest().createResponse()
                .withImsi("asdf").build();
        tunnel.send(response);
    }

    private static void processDeleteSessionResponse(final GtpTunnel tunnel, final Gtp2Message message) {
        // if we are running with Session support, this one will not be called.
    }

    // TODO: needs to move into a Uli convenience builder...
    private static Uli createUli() {
        final var tac = Buffers.wrap((byte) 0x02, (byte) 0x01);
        final var tai = TaiField.of(MccMnc.of("901", "62"), tac);
        final var eci = Buffers.wrap((byte) 0x00, (byte) 0x11, (byte) 0xAA, (byte) 0xBB);
        final var ecgi = EcgiField.of(MccMnc.of("901", "62"), eci);
        return Uli.ofValue(UliType.create().withTai(tai).withEcgi(ecgi).build());
    }

    @Override
    public void run(final GtpConfig configuration, final GtpEnvironment environment) {
        this.environment = environment;
        final var hektorConfig = environment.getConfig().getHektorConfig();
        hektor = Hektor.withName("sgw").withConfiguration(hektorConfig).build();

        // If the PGW is behind a NAT, make sure you grab the public address (duh)
        final var pgw = "127.0.0.1";

        // If you're behind a NAT, you want the NAT:ed address here. Otherwise, your
        // local NIC is fine. All depends where the PGW is...
        final var sgw = "127.0.0.1";
        final var imsi = "999994000000642";

        final var csr = CreateSessionRequest.create()
                .withTeid(Teid.ZEROS)
                .withRat(RatType.EUTRAN)
                .withAggregateMaximumBitRate(10000, 10000)
                .withImsi(imsi)
                .withServingNetwork("310/410")
                .withTliv(createUli())
                .withApnSelectionMode(0)
                .withApn("super")
                .withNoApnRestrictions()
                .withPdnType(IPv4)
                .withIPv4PdnAddressAllocation("0.0.0.0")
                .withNewSenderControlPlaneFTeid()
                .withRandomizedTeid()
                .withIPv4Address(sgw)
                .doneFTeid()
                .withNewBearerContext()
                .withNewSgwFTeid()
                .withRandomizedTeid()
                .withIPv4Address(sgw)
                .doneFTeid()
                .withEpsBearerId(5)
                .withNewBearerQualityOfService(9)
                .withPriorityLevel(10)
                .withPci()
                .doneBearerQoS()
                .doneBearerContext()
                .build();

        environment.initiateNewPdnSession(csr)
                .withRemoteIPv4(pgw)
                .start()
                .thenAccept(session -> {
                    // Note: kicking off a new thread because it is the same thread pool
                    // as the underlying stack.
                    final var t = new Thread(() -> {
                        try {
                            Thread.sleep(100);
                            final var bearer = session.establishDefaultBearer();
                            // bearer.send("165.227.89.76", 52483, "hello world");
                            bearer.send("8.8.8.8", 53, dnsQuery);
                            Thread.sleep(4000);
                            session.terminate();
                        } catch (final Throwable e) {
                            e.printStackTrace();
                        }
                    });
                    t.start();
                });
    }

    public static void main(final String... args) throws Exception {
        final var sgw = new Sgw2();
        sgw.run("sgw.yml");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy