text: /*
   * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The OpenAirInterface Software Alliance licenses this file to You under
   * the terms found in the LICENSE file in the root of this source tree.
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *-------------------------------------------------------------------------------
   * For more information about the OpenAirInterface (OAI) Software Alliance:
   *      contact@openairinterface.org
   */
  
  /*****************************************************************************
    Source     MMEprocess.c
  
    Version        0.1
  
    Date       2013/02/26
  
    Product        NAS stack
  
    Subsystem  MME NAS main process
  
    Author     Frederic Maurel
  
    Description    Implements the Non-Access Stratum protocol for Evolved Packet
    system (EPS) running at the Network side.
  
   *****************************************************************************/
  
  #include "lte/gateway/c/core/oai/include/nas/commonDef.h"
  #include "lte/gateway/c/core/oai/common/log.h"
  #include "lte/gateway/c/core/oai/tasks/nas/util/nas_timer.h"
  
  #include "lte/gateway/c/core/oai/tasks/nas/api/network/network_api.h"
  #include "lte/gateway/c/core/oai/tasks/nas/nas_network.h"
  #include "nas_parser.h"
  
  #include <stdlib.h>  // exit
  #include <poll.h>    // poll
  #include <string.h>  // memset
  #include <signal.h>  // sigaction
  #include <pthread.h>
  
  /****************************************************************************/
  /****************  E X T E R N A L    D E F I N I T I O N S  ****************/
  /****************************************************************************/
  
  /****************************************************************************/
  /*******************  L O C A L    D E F I N I T I O N S  *******************/
  /****************************************************************************/
  
  #define NAS_SLEEP_TIMEOUT 1000 /* 1 second */
  
  static void* _nas_network_mngr(void*);
  
  static int _nas_set_signal_handler(int signal, void(handler)(int));
  static void _nas_signal_handler(int signal);
  
  static void _nas_clean(int net_fd);
  
  /****************************************************************************/
  /******************  E X P O R T E D    F U N C T I O N S  ******************/
  /****************************************************************************/
  
  /****************************************************************************/
  status_code_e main(int argc, const char* argv[]) {
    /*
     * Get the command line options
     */
    if (nas_parser_get_options(argc, argv) != RETURNok) {
      nas_parser_print_usage(FIRMWARE_VERSION);
      exit(EXIT_FAILURE);
    }
  
    /*
     * Initialize logging trace utility
     */
    nas_log_init(nas_parser_get_trace_level());
    const char* nhost = nas_parser_get_network_host();
    const char* nport = nas_parser_get_network_port();
  
    OAILOG_TRACE(INFO, "MME-MAIN  - %s -nhost %s -nport %s -trace 0x%x", argv[0],
                 nhost, nport, nas_parser_get_trace_level());
  
    /*
     * Initialize the Network interface
     */
    if (network_api_initialize(nhost, nport) != RETURNok) {
      OAILOG_TRACE(ERROR, "MME-MAIN  - network_api_initialize() failed");
      exit(EXIT_FAILURE);
    }
  
    int network_fd = network_api_get_fd();
  
    /*
     * Initialize the NAS contexts
     */
    nas_network_initialize();
    /*
     * Initialize NAS timer handlers
     */
    nas_timer_init();
    /*
     * Set up signal handlers
     */
    (void)_nas_set_signal_handler(SIGINT, _nas_signal_handler);
    (void)_nas_set_signal_handler(SIGTERM, _nas_signal_handler);
    pthread_attr_t attr;
  
    pthread_attr_init(&attr);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    /*
     * Start thread use to manage the network connection endpoint
     */
    pthread_t network_mngr;
  
    if (pthread_create(&network_mngr, &attr, _nas_network_mngr, &network_fd) !=
        0) {
      OAILOG_TRACE(ERROR,
                   "MME-MAIN  - "
                   "Failed to create the network management thread");
      network_api_close(network_fd);
      exit(EXIT_FAILURE);
    }
  
    pthread_attr_destroy(&attr);
  
    /*
     * Suspend execution of the main process until the network connection
     * endpoint is still active
     */
    while (network_fd != -1) {
      poll(NULL, 0, NAS_SLEEP_TIMEOUT);
      network_fd = network_api_get_fd();
    }
  
    /*
     * Termination cleanup
     */
    _nas_clean(network_fd);
    OAILOG_TRACE(WARNING, "MME-MAIN  - NAS main process exited");
  }
  
  /****************************************************************************/
  /*********************  L O C A L    F U N C T I O N S  *********************/
  /****************************************************************************/
  
  /****************************************************************************
   **                                                                        **
   ** Name:    _nas_network_mngr()                                       **
   **                                                                        **
   ** Description: Manages the connection endpoint use to communicate with   **
   **      the network sublayer                                      **
   **                                                                        **
   ** Inputs:  fd:        The descriptor of the network connection   **
   **             endpoint                                   **
   **          Others:    None                                       **
   **                                                                        **
   ** Outputs:     Return:    None                                       **
   **          Others:    None                                       **
   **                                                                        **
   ***************************************************************************/
  static void* _nas_network_mngr(void* args) {
    OAILOG_FUNC_IN;
    int ret_code;
    int network_message_id;
    int bytes;
    int* fd = (int*)args;
  
    OAILOG_TRACE(INFO, "MME-MAIN  - Network connection manager started (%d)",
                 *fd);
  
    /*
     * Network receiving loop
     */
    while (true) {
      /*
       * Read the network data message
       */
      bytes = network_api_read_data(*fd);
  
      if (bytes == RETURNerror) {
        /*
         * Failed to read data from the network sublayer;
         * * * * exit from the receiving loop
         */
        OAILOG_TRACE(ERROR,
                     "MME-MAIN  - "
                     "Failed to read data from the network sublayer");
        break;
      }
  
      if (bytes == 0) {
        /*
         * A signal was caught before any data were available
         */
        continue;
      }
  
      /*
       * Decode the network data message
       */
      network_message_id = network_api_decode_data(bytes);
  
      if (network_message_id == RETURNerror) {
        /*
         * Failed to decode data read from the network sublayer
         */
        continue;
      }
  
      /*
       * Process the network data message
       */
      ret_code =
          nas_network_process_data(network_message_id, network_api_get_data());
  
      if (ret_code != RETURNok) {
        /*
         * The network data message has not been successfully
         * * * * processed
         */
        OAILOG_TRACE(WARNING,
                     "MME-MAIN  - "
                     "The network procedure call 0x%x failed",
                     network_message_id);
      }
    }
  
    /*
     * Close the connection to the network sublayer
     */
    OAILOG_TRACE(WARNING,
                 "MME-MAIN  - "
                 "The network connection endpoint manager exited");
    OAILOG_FUNC_RETURN(NULL);
  }
  
  /****************************************************************************
   **                                                                        **
   ** Name:    _nas_set_signal_handler()                                 **
   **                                                                        **
   ** Description: Set up a signal handler                                   **
   **                                                                        **
   ** Inputs:  signal:    Signal number                              **
   **          handler:   Signal handler                             **
   **          Others:    None                                       **
   **                                                                        **
   ** Outputs:     Return:    RETURNerror, RETURNok                      **
   **          Others:    None                                       **
   **                                                                        **
   ***************************************************************************/
  static int _nas_set_signal_handler(int signal, void(handler)(int)) {
    OAILOG_FUNC_IN;
    struct sigaction act;
  
    /*
     * Initialize signal set
     */
    (void)memset(&act, 0, sizeof(act));
    (void)sigfillset(&act.sa_mask);
    (void)sigdelset(&act.sa_mask, SIGHUP);
    (void)sigdelset(&act.sa_mask, SIGINT);
    (void)sigdelset(&act.sa_mask, SIGTERM);
    (void)sigdelset(&act.sa_mask, SIGILL);
    (void)sigdelset(&act.sa_mask, SIGTRAP);
    (void)sigdelset(&act.sa_mask, SIGIOT);
  #ifndef LINUX
    (void)sigdelset(&act.sa_mask, SIGEMT);
  #endif
    (void)sigdelset(&act.sa_mask, SIGFPE);
    (void)sigdelset(&act.sa_mask, SIGBUS);
    (void)sigdelset(&act.sa_mask, SIGSEGV);
    (void)sigdelset(&act.sa_mask, SIGSYS);
    /*
     * Initialize signal handler
     */
    act.sa_handler = handler;
  
    if (sigaction(signal, &act, 0) < 0) {
      return RETURNerror;
    }
  
    OAILOG_TRACE(INFO, "MME-MAIN  - Handler successfully set for signal %d",
                 signal);
    OAILOG_FUNC_RETURN(RETURNok);
  }
  
  /****************************************************************************
   **                                                                        **
   ** Name:    _nas_signal_handler()                                     **
   **                                                                        **
   ** Description: Signal handler                                            **
   **                                                                        **
   ** Inputs:  signal:    Signal number                              **
   **          Others:    None                                       **
   **                                                                        **
   ** Outputs:     Return:    None                                       **
   **          Others:    None                                       **
   **                                                                        **
   ***************************************************************************/
  static void _nas_signal_handler(int signal) {
    OAILOG_FUNC_IN;
    OAILOG_TRACE(WARNING, "MME-MAIN  - Signal %d received", signal);
    _nas_clean(network_api_get_fd());
    exit(EXIT_SUCCESS);
    OAILOG_FUNC_OUT;
  }
  
  /****************************************************************************
   **                                                                        **
   ** Name:    _nas_clean()                                              **
   **                                                                        **
   ** Description: Performs termination cleanup                              **
   **                                                                        **
   ** Inputs:  net_fd:    Network's connection file descriptor       **
   **          Others:    None                                       **
   **                                                                        **
   ** Outputs:     Return:    None                                       **
   **          Others:    None                                       **
   **                                                                        **
   ***************************************************************************/
  static void _nas_clean(int net_fd) {
    OAILOG_FUNC_IN;
    OAILOG_TRACE(INFO, "MME-MAIN  - Perform EMM and ESM cleanup");
    nas_network_cleanup();
    OAILOG_TRACE(INFO, "MME-MAIN  - Closing network connection %d", net_fd);
    network_api_close(net_fd);
    OAILOG_FUNC_OUT;
  }
  