<commit_before>/*
 * main.c
 *
 * FileTea, low-friction file sharing <http://filetea.net>
 *
 * Copyright (C) 2011, Igalia S.L.
 *
 * Authors:
 *   <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * version 3, or (at your option) any later version as published by
 * the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Affero General Public License at http://www.gnu.org/licenses/agpl.html
 * for more details.
 */

#include <evd.h>

#include "filetea-node.h"

#define DEFAULT_HTTP_LISTEN_PORT  8080
#define DEFAULT_HTTPS_LISTEN_PORT 4430
#define DEFAULT_CONFIG_FILENAME "/etc/filetea/filetea.conf"

static EvdDaemon *evd_daemon;

static gchar *config_file = NULL;
static gboolean daemonize = FALSE;
static guint http_port = 0;
static guint https_port = 0;
static GKeyFile *config = NULL;

static FileteaNode *http_node = NULL;
static FileteaNode *https_node = NULL;

static gint setup_pending = 0;

static GOptionEntry entries[] =
{
  { "conf", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Absolute path for the configuration file, default is '" DEFAULT_CONFIG_FILENAME "'", "filename" },
  { "daemonize", 'D', 0, G_OPTION_ARG_NONE, &daemonize, "Run service in the background", NULL },
  { "http-port", 'p', 0, G_OPTION_ARG_INT, &http_port, "Override the HTTP listening port specified in configuration file", "port" },
  { "https-port", 'P', 0, G_OPTION_ARG_INT, &https_port, "Override the HTTPS listening port specified in configuration file", "port" },
  { NULL }
};

static void
finish_setup (void)
{
  GError *error = NULL;
  gchar *user = NULL;

  /* set 'user' as process owner, if specified */
  user = g_key_file_get_string (config, "node", "user", NULL);
  if (user != NULL)
    {
      if (! evd_daemon_set_user (evd_daemon, user, &error))
        goto quit;

      g_free (user);
    }

  g_debug ("Setup completed, FileTea daemon running...");

  return;

 quit:
  g_debug ("%s", error->message);
  g_error_free (error);

  evd_daemon_quit (evd_daemon, -1);
}

static void
node_on_listen (GObject      *service,
                GAsyncResult *result,
                gpointer      user_data)
{
  GError *error = NULL;
  guint *port = user_data;

  if (! evd_service_listen_finish (EVD_SERVICE (service), result, &error))
    goto quit;

  g_debug ("Listening on port %u", *port);

  setup_pending--;
  if (setup_pending == 0)
    finish_setup ();

  return;

 quit:
  g_debug ("ERROR listening on port %u: %s", *port, error->message);
  g_error_free (error);

  evd_daemon_quit (evd_daemon, -1);
}

static void
on_tls_certificate_loaded (GObject      *obj,
                           GAsyncResult *res,
                           gpointer      user_data)
{
  GError *error = NULL;
  EvdTlsCredentials *cred = EVD_TLS_CREDENTIALS (obj);

  if (! evd_tls_credentials_add_certificate_from_file_finish (cred,
                                                              res,
                                                              &error))
    {
      g_debug ("ERROR loading TLS certificate: %s", error->message);
      g_error_free (error);

      evd_daemon_quit (evd_daemon, -1);
    }
  else
    {
      g_debug ("TLS certificate loaded");

      setup_pending--;
      if (setup_pending == 0)
        finish_setup ();
    }
}

static gboolean
setup_https_node (GKeyFile *config, GError **error)
{
  gchar *cert_file;
  gchar *key_file;
  EvdTlsCredentials *cred;
  gchar *addr;
  guint dh_depth;

  /* load X.509 certificate filename from config */
  cert_file = g_key_file_get_string (config, "https", "cert", error);
  if (cert_file == NULL)
    return FALSE;

  /* load X.509 private-key filename from config */
  key_file = g_key_file_get_string (config, "https", "key", error);
  if (key_file == NULL)
    return FALSE;

  /* create Filetea node for HTTPS */
  https_node = filetea_node_new (config, error);
  if (https_node == NULL)
    return FALSE;

  /* activate TLS automatically in the node */
  evd_service_set_tls_autostart (EVD_SERVICE (https_node), TRUE);

  /* obtain TLS credentials object from the node, and load the certificate
     asynchronously */
  cred = evd_service_get_tls_credentials (EVD_SERVICE (https_node));
  evd_tls_credentials_add_certificate_from_file (cred,
                                                 cert_file,
                                                 key_file,
                                                 NULL,
                                                 on_tls_certificate_loaded,
                                                 config);
  setup_pending++;

  /* set Diffie-Hellman parameters into credentials */
  dh_depth = g_key_file_get_integer (config, "https", "dh-depth", error);
  if (dh_depth == 0)
    {
      if ((*error) != NULL)
        return FALSE;
    }
  else
    {
      g_object_set (cred, "dh-bits", dh_depth, NULL);
    }

  /* obtain HTTPS listening port */
  if (https_port == 0)
    {
      https_port = g_key_file_get_integer (config, "https", "port", error);
      if (http_port == 0)
        {
          if (g_error_matches (*error,
                               G_KEY_FILE_ERROR,
                               G_KEY_FILE_ERROR_KEY_NOT_FOUND))
            {
              return FALSE;
            }
          else<commit_msg>Prevents aborting the daemon when 'dh-depth' config option is commented<commit_after>/*
 * main.c
 *
 * FileTea, low-friction file sharing <http://filetea.net>
 *
 * Copyright (C) 2011, Igalia S.L.
 *
 * Authors:
 *   <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * version 3, or (at your option) any later version as published by
 * the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Affero General Public License at http://www.gnu.org/licenses/agpl.html
 * for more details.
 */

#include <evd.h>

#include "filetea-node.h"

#define DEFAULT_HTTP_LISTEN_PORT  8080
#define DEFAULT_HTTPS_LISTEN_PORT 4430
#define DEFAULT_CONFIG_FILENAME "/etc/filetea/filetea.conf"

static EvdDaemon *evd_daemon;

static gchar *config_file = NULL;
static gboolean daemonize = FALSE;
static guint http_port = 0;
static guint https_port = 0;
static GKeyFile *config = NULL;

static FileteaNode *http_node = NULL;
static FileteaNode *https_node = NULL;

static gint setup_pending = 0;

static GOptionEntry entries[] =
{
  { "conf", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Absolute path for the configuration file, default is '" DEFAULT_CONFIG_FILENAME "'", "filename" },
  { "daemonize", 'D', 0, G_OPTION_ARG_NONE, &daemonize, "Run service in the background", NULL },
  { "http-port", 'p', 0, G_OPTION_ARG_INT, &http_port, "Override the HTTP listening port specified in configuration file", "port" },
  { "https-port", 'P', 0, G_OPTION_ARG_INT, &https_port, "Override the HTTPS listening port specified in configuration file", "port" },
  { NULL }
};

static void
finish_setup (void)
{
  GError *error = NULL;
  gchar *user = NULL;

  /* set 'user' as process owner, if specified */
  user = g_key_file_get_string (config, "node", "user", NULL);
  if (user != NULL)
    {
      if (! evd_daemon_set_user (evd_daemon, user, &error))
        goto quit;

      g_free (user);
    }

  g_debug ("Setup completed, FileTea daemon running...");

  return;

 quit:
  g_debug ("%s", error->message);
  g_error_free (error);

  evd_daemon_quit (evd_daemon, -1);
}

static void
node_on_listen (GObject      *service,
                GAsyncResult *result,
                gpointer      user_data)
{
  GError *error = NULL;
  guint *port = user_data;

  if (! evd_service_listen_finish (EVD_SERVICE (service), result, &error))
    goto quit;

  g_debug ("Listening on port %u", *port);

  setup_pending--;
  if (setup_pending == 0)
    finish_setup ();

  return;

 quit:
  g_debug ("ERROR listening on port %u: %s", *port, error->message);
  g_error_free (error);

  evd_daemon_quit (evd_daemon, -1);
}

static void
on_tls_certificate_loaded (GObject      *obj,
                           GAsyncResult *res,
                           gpointer      user_data)
{
  GError *error = NULL;
  EvdTlsCredentials *cred = EVD_TLS_CREDENTIALS (obj);

  if (! evd_tls_credentials_add_certificate_from_file_finish (cred,
                                                              res,
                                                              &error))
    {
      g_debug ("ERROR loading TLS certificate: %s", error->message);
      g_error_free (error);

      evd_daemon_quit (evd_daemon, -1);
    }
  else
    {
      g_debug ("TLS certificate loaded");

      setup_pending--;
      if (setup_pending == 0)
        finish_setup ();
    }
}

static gboolean
setup_https_node (GKeyFile *config, GError **error)
{
  gchar *cert_file;
  gchar *key_file;
  EvdTlsCredentials *cred;
  gchar *addr;
  guint dh_depth;

  /* load X.509 certificate filename from config */
  cert_file = g_key_file_get_string (config, "https", "cert", error);
  if (cert_file == NULL)
    return FALSE;

  /* load X.509 private-key filename from config */
  key_file = g_key_file_get_string (config, "https", "key", error);
  if (key_file == NULL)
    return FALSE;

  /* create Filetea node for HTTPS */
  https_node = filetea_node_new (config, error);
  if (https_node == NULL)
    return FALSE;

  /* activate TLS automatically in the node */
  evd_service_set_tls_autostart (EVD_SERVICE (https_node), TRUE);

  /* obtain TLS credentials object from the node, and load the certificate
     asynchronously */
  cred = evd_service_get_tls_credentials (EVD_SERVICE (https_node));
  evd_tls_credentials_add_certificate_from_file (cred,
                                                 cert_file,
                                                 key_file,
                                                 NULL,
                                                 on_tls_certificate_loaded,
                                                 config);
  setup_pending++;

  /* set Diffie-Hellman parameters into credentials */
  dh_depth = g_key_file_get_integer (config, "https", "dh-depth", error);
  if (dh_depth == 0)
    {
      if ((*error) != NULL)
        {
          if (! g_error_matches (*error,
                                 G_KEY_FILE_ERROR,
                                 G_KEY_FILE_ERROR_KEY_NOT_FOUND))
            {
              return FALSE;
            }
          else
            {
              g_clear_error (error);
            }
        }
    }
  else
    {
      g_object_set (cred, "dh-bits", dh_depth, NULL);
    }

  /* obtain HTTPS listening port */
  if (https_port == 0)
    {
      https_port = g_key_file_get_integer (config, "https", "port", error);
      if (http_port == 0)
        {
          if (g_error_matches (*error,
                               G_KEY_FILE_ERROR,
                               G_KEY_FILE_ERROR_KEY_NOT_FOUND))
            {
              return FALSE;
            }
          else
{'fraction_non_alphanumeric': 0.10217315106905012, 'fraction_numerical': 0.005958640028040659, 'mean_word_length': 2.356764705882353, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '711437', 'n_tokens_mistral': 3629, 'n_tokens_neox': 3518, 'n_words': 1004}