EpcTools
An event based multi-threaded C++ development framework.
|
EpcTools is a set of C++ classes that simplifies the development and management of EPC applications. This library is intended for use on any Linux based system that supports g++ and pthreads.
Update your system.
Install Ubuntu 16.04 prerequisites.
Install Ubuntu 18.04 prerequisites.
Clone the project, install the dependencies (via configure), build the static library and install.
To compile with optimization disabled run the following
EpcTools is configured via a JSON configuration file. Additionally, application specific configuration items may be defined in the same JSON configuration file and also on the command line. The options contained in JSON configuration file(s) and command line arguments can be accessed via an instance of EGetOpt.
Multiple JSON configuration files can be loaded by EGetOpt.
Sample JSON Configuration File
These JSON configuration parameters can be loaded and access by EGetOpt as follows:
Command line options can be accessed by defining and loading the options using EGetOpt. The two different types of command line arguments are named and positional.
Named arguments have a short and/or long name, a data type and may have an optional or required parameter. An example of a short and long name of an argument are "-f" and "--file". Named arguments can be present in any order in the command line (they can even be intermixed with positional arguments).
A positional argument is a string argument that is referenced by a zero based index.
Here is an example command line and the associated JSON representation of those arguments stored by EGetOpt:
Here is a corresponding code example parsing and accessing command line arguments:
See EGetOpt for more information.
For some classes, EpcTools supports the concept of public classes and private. A public class/object is one that can be accessed from a different process, while a private class/object can only be accessed from within the current process. This is achieved by storing the data associated with the public object in shared memory, thereby giving access to the public objects to any process.
NOTE: Since public objects have data stored in shared memory, each application that wants to have access to the public object must enable the EpcTools/EnablePublicObjects configuration option to TRUE. By default, the EpcTools/EnablePublicObjects configuration option is FALSE
. Additionally, if an application does not call EpcTools::UnInitialize() prior to exiting, the objects in shared memory will be remain until the shared memory is released. This condition can lead to unexpected/unexplained application behavior.
The classes that support public/private are:
Public | Private | Description |
---|---|---|
EMutexPublic | EMutexPrivate | A mutex (mutual exclusion object) is a program object that is created so that multiple threads can take turns sharing the same resource, such as a file or list. An application can attach to a public mutex specifying the mutex ID when calling the attach() method. |
ESemaphorePublic | ESemaphorePrivate | A semaphore is simply a variable which is non-negative and shared between threads. The EpcTools semaphore is what is considered a counting semaphore. Semaphores are used internally in EpcTools as part of various queue implementations to represent the number of messages in the queue. If you attempt to read a queue that is empty, the semaphore will block until a message has been added to the queue. An application can attach to a public semaphore by specifying the semaphore ID when calling the attach() method. |
EQueuePublic | EQueuePrivate | A message queue is a FIFO (first in first out) list of messages. Since these messages may be shared across processes, pointer values are not allowed. A message class derived from EMessage provides utilities to pack and unpack data that can be written to and read from a queue. An application can attach to a public queue by specifying the queue ID when calling the init() method. |
EThreadPublic | EThreadPrivate | A thread provides multiple threads of execution within the same program in a shared memory address space. Threads allow for concurrent programming and, on multiple processor/core systems, true parallelism. To send an event message to a public thread from a different process, the application must first create an instance of EThreadPublic that refers to the same application ID and thread ID that the target thread was initialized with. |
Inter process communication through shared memory is a concept where two or more processes can access the common memory and changes to the shared memory made by one process can viewed (and changed) by another process. The ESharedMemory class provides functionality to allocate, access and release a shared memory block. Once created, a pointer to the shared memory can be retrieved using the getDataPtr() method. Concurrent access to the shared memory should be controlled via an instance of EMutexPublic.
This example either creates or attaches to the shared memory identified by the file "/tmp/sm1"
and a shared memory ID of 1 and is 1MB in size. The variable p
is assigned the first address of the 1MB shared memory block. When sm
goes out of scope, the shared memory will be released if no other clients are attached.
A basic thread is a thread wrapper that will execute a user provided procedure/function in a separate thread. The basic thread is defined by deriving a class from EThreadBasic and overloading the threadProc()
method. To initialize and start the thread simply call the init(pVoid arg, Dword stackSize = 0)
method. Call join() to wait for the thread to exit. Other useful EThreadBasic methods include sleep(Int milliseconds) and yield().
In this example, a basic thread is defined in the class EThreadBasicTest
.
An event thread responds to event messages sent to the thread by invoking the associated message handler method defined in the class. The event message queue for the thread can either be allocated from the heap, a private event thread, or allocated from shared memory, a public event thread. EThreadEvent is a templated class that takes two parameters 1) the queue class and 2) the event message class to be used for this thread.
The two event queue template classes, EThreadQueuePublic and EThreadQueuePrivate, each take a template parameter of an event message class. EThreadQueuePublic creates the event queue in shared memory allowing thread events to be posted from any process, and EThreadQueuePrivate creates the event queue on the heap which limits thread events to only be posted from within the same process.
The event message object will be passed to the event handler method defined in the derived thread class. The basic functionality of an event message is encapsulated in the EThreadEventMessageBase and contains the event message ID and a timer that measures the amount of time an event message spends in the event queue. Additionally, the event message must contain a void pointer. This is needed to distribute timer events.
The standard implementation of an event message is contained in EThreadMessage. The event data for this class is a union defined as follows:
EThreadMessage has several overloaded constructors that can populate various elements of the union. Additionally, one constructor takes a reference to an instance of EThreadEventMessageData which provides the developer with the ability to initialize any combination of union members.
A custom or user-defined event message class can be used for a thread by developing the following classes:
NOTE: The custom event data object must provide access to a void pointer and provide definitions for EThreadEventMessageDataBase::getVoidPtr() and EThreadEventMessageDataBase::setVoidPtr().
Standard Events and Callbacks
Event | Callback Method | Description |
---|---|---|
EM_INIT | onInit() | The EM_INIT message will is posted to the thread when the thread is started. Normally, this is the first message that will be processed. However, for a public thread, it is possible that the process sending thread events could start before the thread is started which would result in the EM_INIT event to not be the first event processed. |
EM_QUIT | onQuit() | This event is posted to the thread when the quit() method is invoked on the thread. This will be the last event processed by the thread before the thread exits. |
EM_SUSPEND | onSuspend() | This event is posted to a thread when the suspend() method has been invoked. This will be the last event processed prior to the thread suspending event processing. |
EM_TIMER | onTimer() | The EM_TIMER event will be posted to a thread when a timer associated with the thread expires. A pointer to the timer object that has expired is included as an argument to the onTimer() method. |
User defined events ID's start with EM_USER. The association between the event ID and the event handler is defined in the message map. The following macros are used for declaring the message map and creating the association between the event ID and the event handler.
Message Map Macros
Macro | Arguments | Description |
---|---|---|
DECLARE_MESSAGE_MAP() | None | This macro must appear in the class definition. It's inclusion will create the necessary definitions within the class to support the message map definition and usage. |
BEGIN_MESSAGE_MAP() | The class The base class | This macro starts the definition of the message map. The first argument is the current class name and the second argument is base class of the current class. |
ON_MESSAGE() | Event ID Event handler method | Each user event that is to be handled by the class must have an entry in the message map that establishes the association between the event ID and the event handler method. The event handler method name must be fully qualified. |
END_MESSAGE_MAP() | None | This macro closes the message map declaration. |
The message map declaration within the class should be performed as follows:
The definition of the message map should happen in code as follows:
When an event is posted to the thread's event queue, the thread will dequeue the event message and call the event handler associated with the event ID. This process is referred to as event dispatching. The association between the event ID and the event handler is defined in the message map.
In this example, EThreadTest
is derived from EThreadPrivate and there are two event handlers defined in EThreadTest
: userFunc1()
and userFunc2()
. According to the message map, when event EM_USER1
is received, the dispatcher will call userFunc1()
and when EM_USER2
is received, the dispatcher will call userFunc2()
.
The event dispatcher searches the message map looking for the event ID. If the event ID is not found, the dispatcher will then search the parent class which is the second parameter in the BEGIN_MESSAGE_MAP
macro. This process will continue until a handler is identified or there are no more base classes to evaluate. In this case, the defMessageHandler() will be called to process the message.
The above example demonstrates the inheritance behavior of the event dispatcher. When an instance of EThreadTestParent
is created and EM_USER1
is sent to it, EThreadTestParent::userFunc1()
will be called to process the event. Similarly, when an instance of EThreadTestChild
is created and EM_USER1
is sent to it, EThreadTestChild::childUserFunc1()
will be called. Finally, when EM_USER2
is sent to the instance of EThreadTestChild
, the event dispatcher will call EThreadTestParent::userFunc2()
to process the event message since there isn't an event handler defined in EThreadTestChild
to process EM_USER2
.
EThreadEvent supports two types of timers: a periodic timer and a one-shot timer. A periodic timer will emit a timer expiration event X number of milliseconds as defined by the interval of the timer. These timer expiration events will continue until the timer is stopped or destroyed. By contrast, a one-shot timer will generate a single timer expiration event after the duration specified by the timer's interval value.
Both timer types, periodic and one-shot, are represented by the EThreadEventTimer class.
Periodic Timer Setup
This example will create a periodic timer that will expire once every 1,000 milliseconds (1 second). Each time the timer expires, the onTimer() method of the mythread
object will be invoked.
One-Shot Timer Setup
This example will create a one-shot timer that will expire after 1,000 milliseconds (1 second). The timer can be re-used by calling mytimer.start()
.
Both periodic and one-shot timers can be stopped by calling the timer stop()
method.
In this example, the has 2 timers that are associated with it, the periodic timer and the overall timer. When the periodic timer expires, for example every 1 second, the onTimer() method will be called which will in turn send the MYEVENT event to the thread which will in turn invoke the myhandler() thread event handler method. When the overall timer expires, for example after 10 seconds, the onTimer() method will call quit() which will trigger the onQuit method to be invoked and the thead will exit. Both timers are initialized and started when the thread is started and invokes the onInit() method. The threadExample() function instantiates the thread and waits for the thread to exit.
The benefit of a public event thread over a private event thread is that thread event messages can be sent from a thread in one process to a thread in another process. This is achieved by storing the event message queue in shared memory. When a process creates an instance of a thread class that has a event message queue derived from EThreadQueuePublic the event message queue will be stored in shared memory. The application ID and thread ID that the thread is initialized with are used to uniquely identify the event message queue in shared memory.
Here is sample code for the application that will host the public thread.
And here is sample code for the application that will send event messages.
You will notice that application that will send the messages creates an instance of the thread queue object and the application that will host the thread and process the thread events creates an instance of the thread class.
NOTE: Timing is important. The application that starts first will create the event message queue in shared memory. If this is the application that only sends messages, then it is possible that this application can start posting messages to the event queue before the thread has started. When the application where the thread will exist starts, it will post an EM_INIT
message to the thread's event message queue which will trigger the onInit() method to be called. Depending on which application starts first, it is possible that other events will be processed by the thread before the EM_INIT
event is processed.
EpcTools supports several synchronization mechanisms which can be used to synchronize operations in multiple threads and processes.
Type | Private | Public |
---|---|---|
Mutex | EMutexPrivate | EMutexPublic |
Semaphore | ESemaphorePrivate | ESemaphorePublic |
Event | EEvent | N/A |
Read/Write Lock | ERWLock | N/A |
A mutual exclusion or mutex allows for resource sharing by limiting access to that resource to a single thread. An example of this would be to limit adding and removing entries to a linked list to a single thread since performing maintenance on the linked list from multiple threads would most likely cause the list pointers to become corrupted.
A private mutex is allocated from the stack or heap and provides a locking mechanism to threads in the same process. Mutex Example
A public mutex is allocated from shared memory and provides synchronization to a single resource across processes. Multiple processes can gain access to the same mutex by attaching to an existing mutex using the mutex ID. The process that creates the mutex does so by simply declaring the mutex. The mutex ID can be retrieved by using the mutexId() method.
Another process can attach to an existing mutex by bypassing the mutex initialization and calling the attach() method. The method that the "other" process finds out about the mutex ID is up to the application developer. Locking of a public mutex is performed the same way that a private mutex is locked.
Public Mutex Attach Example
Locking a Mutex
A mutex can be locked by creating an instance of EMutexLock which takes a reference to EMutexData in it's constructor. Both the EMutexPrivate and EMutexPublic are derived from EMutexData, so either object can be passed as the constructor argument. By default, the EMutexLock constructor will wait for the lock to be obtained when object is created. However, an optional flag can be passed to the EMutexLock constructor to not acquire the lock. In this case, the lock can be manually acquired by calling acquire(Bool wait=True). If wait
is True, acquire() will block until the lock can be obtained. If wait
is False
and the lock cannot immediately obtained, acquire() will return False indicating that the lock was not obtained.
Regardless of how the lock was obtained, when the EMutexLock object goes out of scope, the lock on the mutex will be released.
Mutex Lock Example
A counting semaphore is simply a numeric variable that can be incremented and decremented. For example, a semaphore could represent the number of records in a queue or the number of free entries in a pre-allocated array.
A semaphore value can be incremented using the Increment() method, and the semaphore value can be decremented using the Decrement(Bool wait=True) method. When Decrement(Bool wait=True) is called, if the numeric value is zero and wait
is True
, the function will block until the value is greater than zero before decrementing it. Decrement(Bool wait=True) returns True
if the value was successfully decremented and False
if the value was not successfully decremented.
A semaphore can be either public or private as represented by ESemaphorePublic and ESemaphorePrivate.
An event object is an object that can be waited on for something to occur. An example could be waiting for a process to complete.
Event Example
An Read/Write lock allows concurrent access for read-only operations, while write operations require exclusive access. An example of this is accessing a list would obtain a read lock while updating the list would require a write lock. When a write lock is obtained, it will prevent other read and/or write locks from being granted. Similarly, if a write lock is requested and there is one or more active read locks, the write will only be granted after the read locks have been released.
Read/Write Lock Example In this example, two threads will be created that will obtain read locks and a third thread will be created that will obtain a write lock. These threads will run in different combinations that will demonstrate that multiple read locks can be obtained concurrently and only a single exclusive (of other read and write locks) write can be obtained at a time.
Asynchronous socket communications is supported by EpcTools in the ESocket namespace. Currently, support for IPv4 and IPv6 with both TCP and UDP have been implemented. The framework can be enhanced to support additional socket types such as Unix domain socket.
ESocket::Thread is derived from EThreadEvent and has a custom message pump and dispatcher to identify and process socket events for sockets that are registered with the socket thread. The message pump function utilizes select()
to detect when a socket can be read from, written to or when an error has occurred. These events are then dispatched to appropriate callback methods depending on the role and state of the socket.
In addition to processing socket events ESocket::Thread is also capable of processing standard event messages. See Event Thread for more information.
Since ESocket::Thread is derived from EThreadEvent, ESocket::Thread supports either a public or a private event message queue with the option of either EThreadMessage or a custom event thread message.
Example Socket Thread
TCP is a streaming connection based protocol. As such, a TCP application will either act as a client (connects to a server) or as a server (accepts connections from clients). The ESocket::TCP namespace contains the class definitions used by the client and server applications.
A server application listens for incoming connections using a class derived from TCP::Listener. When the listener detects an incoming connection, the TCP::Listener::createSocket() method will be called to create an instance of a class derived from TCP::Talker that will be used to received data from and send data to the client.
Conversely, a client application initiates a connection to a server by calling the connect() method with the IP address, IPv4 or IPv6, and port of the server. When the connection is complete, the onConnect() method of the socket object will be called by the dispatcher indicating that the connection is up and communication can proceed.
TCP::Listener Events
Event | Callback Method | Description |
---|---|---|
Read | TCP::Talker::onConnect | A listening socket will indicate that it can be read from when a new client connects. The internals will create a new TCP::Talker object to handle the new connection by calling the TCP::Listener::createSocket() method. Once the talking object has been created, the dispatcher will then call the TCP::Talker::onConnect() method to start communication with the new client. |
Write | None | This event is not applicable to a listening socket. |
Error | TCP::Listener::onError | Indicates that an error has occurred on the socket while listening for new connections. |
Example TCP Listener
TCP::Talker Events
Event | Callback Method | Description |
---|---|---|
Read | TCP::Talker::onReceive TCP::Talker::onClose | When a talking socket indicates that it can be read, the framework calls recv() to read any pending data. If zero bytes are read, the socket has been closed and the dispatcher will call the TCP::Talker::onClose() method. If more than zero bytes are read, the data is inserted it into an internal receive buffer and the dispatcher will call the TCP::Talker::onReceive() method allowing the application to process the data that has been read. |
Write | None | The framework processes the write event by attempting to send any unsent data to the peer. No application interaction is required to process this event. |
Error | TCP::Talker::onError | Indicates that an error has occurred on the socket. |
Example TCP Talker
UDP is a connectionless message based protocol. Messages are sent to specific IP/ports and received from a specific IP/port. A UDP socket must be bound to a local port and IP address to receive messages.
Example UDP Thread
UDP Events
Event | Callback Method | Description |
---|---|---|
Read | UDP::onReceive | When a UDP socket indicates that it can be read, the framework calls recvfrom() to read any pending data. If more than zero bytes are read, the data is inserted it into an internal receive buffer and the dispatcher will call the UDP::onReceive() method allowing the application to process the data that has been read. |
Write | None | The framework processes the write event by sending any unsent messages to the destination. No application interaction is required to process this event. |
Error | UDP::onError | Indicates that an error has occurred on the socket. |
Example UDP Socket
Logging in EpcTools is performed by the ELogger class and configured in the JSON configuration file or in code. Multiple logs can be defined with each log identified by a unique integer identifier (e.g. 1, 2, 99). Each log can have it's messages written to one or more destinations (sinks). The log messages are written by a background thread. The number of threads writing the log messages and the queue size for each thread are defined in the Logger configuration.
The JSON logger configuration is defined in the Logger configuration section of the EpcTools configuration file. Example JSON Logger Configuration
JSON Configuration Elements
Event | Callback Method | Description |
---|---|---|
Read | UDP::onReceive | When a UDP socket indicates that it can be read, the framework calls recvfrom() to read any pending data. If more than zero bytes are read, the data is inserted it into an internal receive buffer and the dispatcher will call the UDP::onReceive() method allowing the application to process the data that has been read. |
Write | None | The framework processes the write event by sending any unsent messages to the destination. No application interaction is required to process this event. |
Error | UDP::onError | Indicates that an error has occurred on the socket. |
The following code configures ELogger the same as the JSON configuration example.
A sink set defines a set of outputs or sinks. Once defined, a sink set is then associated with a log. If the same sink set is associated with more than one log, then each of the associated logs will have their log messages written to the same sinks.
Sink Types
Class | Parameters | Description |
---|---|---|
ELoggerSinkSyslog | loglevel pattern | Message will be written to syslog. |
ELoggerSinkStdout | loglevel pattern | Message will be written to the standard output (stdout) file handle. |
ELoggerSinkStderr | loglevel pattern | Message will be written to the standard error (stderr) file handle. |
ELoggerSinkBasicFile | loglevel pattern filename truncate | Message will be written to a file. If the truncate flag is true, then the file will be truncated at startup. |
ELoggerSinkRotatingFile | loglevel pattern filename max_size_mb max_files rotate_on_open | Message will be written to a series of files. When a file reaches the maximum file size defined by max_size_mb, the next file in the series will be opened and written to. ELogger will keep a maximum of max_files previous log files (including the current file). |
ELoggerSinkDailyFile | loglevel pattern filename truncate rollover_hour rollover_minute | Message will be written to a file. When the hour and minute specified by rollover_hour and rollover_minute are reached, the current log file will be closed and a new log file will be opened. The system date and time will be appended to the log file name. |
A log definition includes a log category, a string that can be output with each log message, a sink set which defines the sinks that the log messages will be written to, a log identifier used to identify the log when writing a log message and the minimum log level at which log messages will be written to associated sink set sinks.
When a log message is written a log level is included that represents the severity or importance of the log message. Each sink and log also has a log level associated with it. These log levels represent the minimum log level that will be output to the sink or log.
Log Levels in Ascending Order of Importance
Log Level | Enumeration |
---|---|
Debug | ELogger::eDebug |
Informational | ELogger::eInfo |
Startup | ELogger::eStartup |
Minor | ELogger::eMinor |
Major | ELogger::eMajor |
Critical | ELogger::eCritical |
Off (suppresses all messages) | ELogger::eOff |
Examples
A DNS Cache, represented by DNS::Cache, is defined as one or more DNS servers that can provide access to the same information. This set of DNS servers is represented by a cache identifier, a unique integer. Accessing the cache instance, DNS::Cache::getInstance(), will create the DNS cache if it does not already exist.
The first step in preparing a DNS cache for use is to configure the global settings as it relates to refreshing entries in the cache based on their TTL (time to live). Queries that have been previously processed by a DNS cache are refreshed prior to their expiration time. This ensures that if the same query is executed that the results will come from the cache instead of having to wait for the query to be sent to a DNS server. The refresh process occurs in the background.
Settings
Method | Description |
---|---|
DNS::Cache::setRefreshConcurrent() | The maximum of refresh DNS queries that will run concurrently. This is a throttling mechanism to ensure that not all refresh queries are submitted at exactly the same time. |
DNS::Cache::setRefreshPercent() | This percentage indicates when a cached DNS query will be eligible to be refreshed as a percentage of it's TTL (time to live). |
DNS::Cache::setRefreshInterval() | This duration, in milliseconds, defines how often the system will check to see of there are any cached DNS queries that are eligible to be refreshed. |
Once these global DNS::Cache settings have been configured, a DNS cache is configured by adding the named servers to the DNS cache.
In this case, three DNS servers have been defined to provide access to the same information. The underlying DNS library, c-ares, handles when a query is sent to a specific DNS server.
DNS::Cache provides a feature that will periodically save the DNS queries that are in the DNS cache (only the query, not the result) to a file. This file can then be loaded at startup to "prime" the cache.
DNS queries can be submitted either synchronously or asynchronously via a DNS cache object DNS::Cache::getInstance(). The query will first check to see if there is an unexpired result in the cache. If the query is in the cache and the results have not expired, the query results will be immediately returned to the caller. If not, the query is sent to a DNS server to be processed. When the results are received, the cache is updated and the result is forwarded to the caller.
Synchronous DNS Query A synchronous DNS query will wait for the query to be processed before returning. Depending on the configuration, this can take several seconds, so care should be taken. A DNS::QueryPtr, which is a shared pointer to a DNS::Query object, is returned. From this pointer, the results of the query can be accessed.
Example Synchronous DNS Query
Asynchronous DNS Query
An asynchronous DNS query functions essentially the same, except that a callback function is called with the DNS::QueryPtr containing the results instead of returning the DNS::QueryPtr. The callback function is defined as follows:
If the query results will can be obtained from the cache, the callback function will be called from the same thread that submitted the query. Otherwise, the callback function will be called from a different thread.
Example Asynchronous DNS Query
3GPP TS 29.303 defines the procedures for EPC node discovery and selection. EpcTools supports the process as it relates to DNS in the EPCDNS namespace. This support includes the construction of node names in EPCDNS::Utility, various node selection wrappers and colocation determination.
Supported Node Names
Node | Example |
---|---|
Home Network | mnc990.mcc311.3gppnetwork.org |
Home Network Gprs | mnc990.mcc311.gprs |
TAI FQDN | tac-lb0A.tac-hb1B.tac.epc.mnc990.mcc311.3gppnetwork.org |
MME FQDN | mmec0A.mmegi1B.mme.epc.mnc990.mcc311.3gppnetwork.org |
MME Pool FQDN | mmegi1B.mme.epc.mnc990.mcc311.3gppnetwork.org |
RAI FQDN | rac01AB.lac23CD.rac.epc.mnc990.mcc311.3gppnetwork.org |
RNC FQDN | rnc01AB.rnc.epc.mnc990.mcc311.3gppnetwork.org |
SGSN FQDN | nri01AB.rac23CD.lac45EF.rac.epc.mnc990.mcc311.3gppnetwork.org |
EPC Nodes Domain FQDN | node.epc.mnc990.mcc311.3gppnetwork.org |
EPC Node FQDN | nodename.node.epc.mnc990.mcc311.3gppnetwork.org |
Non-Emergency ePDG OI FQDN | epdg.epc.mnc990.mcc311.pub.3gppnetwork.org |
Non-Emergency ePDG TAI FQDN | tac-lb0A.tac-hb1B.tac.epdg.epc.mnc990.mcc311.pub.3gppnetwork.org |
Non-Emergency ePDG LAC FQDN | lac01AB.epdg.epc.mnc990.mcc311.pub.3gppnetwork.org |
Non-Emergency ePDG Visited Country FQDN | epdg.epc.mcc311.visited-country.pub.3gppnetwork.org |
Emergency ePDG OI FQDN | sos.epdg.epc.mnc990.mcc311.pub.3gppnetwork.org |
Emergency ePDG TAI FQDN | tac-lb0A.tac-hb1B.tac.sos.epdg.epc.mnc990.mcc311.pub.3gppnetwork.org |
Emergency ePDG LAC FQDN | lac01AB.sos.epdg.epc.mnc990.mcc311.pub.3gppnetwork.org |
Emergency ePDG Visited Country FQDN | sos.epdg.epc.mcc311.visited-country.pub.3gppnetwork.org |
Global eNodeB ID | enb.12AB.enb.epc.mnc990.mcc311.3gppnetwork.org |
Local Home Network FQDN | lhn.mynetwork.lhn.epc.mcc311.visited-country.pub.3gppnetwork.org |
EPC | epc.mnc990.mcc311.3gppnetwork.org |
APN FQDN | apn1.apn.epc.mnc990.mcc311.3gppnetwork.org |
APN | apn1.apn.mnc990.mcc311.3gppnetwork.org |
Diameter FQDN | diameter.epc.mnc990.mcc311.3gppnetwork.org |
Node Selection Wrappers
Node Selector | Description |
---|---|
EPCDNS::ENodeBUPFNodeSelector | Used to identify a set of UPF's associated with an eNodeB. This is used by the NGIC-RTC SGW-C to identify SGW-U's that have been associated with a specific eNodeB. |
EPCDNS::EpcNodeSelector | Used for general EPC node selection based on the node name. |
EPCDNS::MMENodeSelector | Used to identify the MME using the MME code using the MME group identifier. |
EPCDNS::PGWNodeSelector | Used by the SGW-C to identify a list of SGW-C's that can provide access to the requested APN. |
EPCDNS::PGWNodeSelector | Used by the PGW-C to identify a list of PGW-U's by querying for the APN associated with the bearer. |
EPCDNS::SGWNodeSelector | Used by the MME to identify a list of SGW-C's querying for the TAI FQDN supporting an x_3gpp_sgw service or by issuing a Node query looking for a specific node that supports the x_3gpp_sgw service. |
EPCDNS::SGWUPFNodeSelector | Used by the SGW-C to identify a list of SGW-U's by querying for the TAI FQDN supporting an x_3gpp_upf service or by issuing a Node query for the eNodeB that supports the x_3gpp_upf service. |
See EPCDNS::AppServiceEnum for a list of supported services. See EPCDNS::AppProtocolEnum for a list of supported protocols.
Node colocation is used to order two sets of nodes based on topological distance, closest to furthest. For example, you might want to find an SGW-U that is as close as possible to a particular eNodeB. Colocation is your answer. The process takes two EPCDNS::NodeSelectorResult objects which each contain a list of candidates and compares each element in the first EPCDNS::NodeSelectorResult object to each element in the seconds EPCDNS::NodeSelectorResult and calculates a score based on the topon node names. Once complete, the process returns a list of pairs of nodes comprising all combinations of both lists ordered by score, closest to furthest.
See 3GPP TS 29.303 for more information on topon, topoff and colocation (Appendix C-4).
Colocation Example
RFC 6408 defines how DNS can be used to locate hosts that support specific DNS applications. The EPCDNS contains DiameterSelector which is used to locate diameter applications in DNS. After setting the realm, application and protocol, DiameterSelector.process() will return a list of DiameterNaptr objects representing the nodes that support the requested application and protocol.
Refer to DiameterApplicationEnum for a list of supported applications.
Refer to DiameterProtocolEnum for a list of supported protocols.
EManagementEndpoint and EManagementHandler are classes that implement a REST server for the purpose of providing a management interface which can be used to retrieve run-time statistics or set run-time configuration values. The REST server is built using pistache. EManagementEndpoint](EManagementEndpoint) represents the REST server and classes derived from EManagementHandler process the individual REST requests.
To add a handler, perform the following steps:
NOTE: The reference to the ELogger object passed in to the EManagementHandler constructor will be called each time the handler is accessed recording the time, user name and operation that was performed. The user name is obtained from a custom header that is required when submitting a request.
Example Initialization
Example GET Handler This handler returns the current statistics stored in EStatistics.
Example PUT Handler This handler sets the current message counts to zero that are stored in EStatistics.
Example Handler Calls
Class | Description |
---|---|
EString | Derived from std::string, EString adds additional string functionality including format(), tolower(), toupper(), ltrim(), rtrim(), trim(), replaceAll() and replaceAllCopy(). |
EUtility | General functionality that did not warrant a separate class. Static methods include indexOf, indexOfAny(), lastIndexOfAny(), split(), replaceAll(), replaceAllCopy(), string_format(), copy_file(), delete_file(), file_exists(), currentTime(). |
ETime | Used for storing and manipulating the date and time. |
ETimer | A stopwatch like timer that can measure durations in milliseconds or microseconds. |
EPath | A class for manipulating file and directory names. |
EDirectory | A class for accessing files in a directory. |
EError | An exception object that extends std::exception. |
EHash | Calculates a hash value for a string or byte array. |
EBzip2 | Writes and reads bzip compressed files. |
ECircularBuffer | Implements a thread safe circular buffer over a byte array. |