/****************************************************************************
 * apps/wireless/wapi/src/wapi.c
 *
 *   Copyright (C) 2011, 2017Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <gnutt@nuttx.org>
 *
 * Largely and original work, but highly influenced by sampled code provided
 * with WAPI:
 *
 *   Copyright (c) 2010, Volkan YAZICI <volkan.yazici@gmail.com>
 *   All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of  source code must  retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of  conditions and the  following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "wireless/wapi.h"
#include "util.h"

/****************************************************************************
 * Private Types
 ****************************************************************************/

/* Describes one command */

struct wapi_command_s
{
  FAR const char *name;
  uint8_t noptions;
  CODE void *handler;
};

/* Generic form of a command handler */

typedef void (*cmd1_t)(int sock, FAR const char *arg1);
typedef void (*cmd2_t)(int sock, FAR const char *arg1,
                       FAR const char *arg2);
typedef void (*cmd3_t)(int sock, FAR const char *arg1,
                       FAR const char *arg2, FAR const char *arg3);

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

static int wapi_str2int(FAR const char *str);
static double wapi_str2double(FAR const char *str);
static unsigned int wapi_str2ndx(FAR const char *name, FAR const char **list,
                                 unsigned int listlen);

static void wapi_show_cmd(int sock, FAR const char *ifname);
static void wapi_ip_cmd(int sock, FAR const char *ifname,
                        FAR const char *addrstr);
static void wapi_mask_cmd(int sock, FAR const char *ifname,
                          FAR const char *maskstr);
static void wapi_freq_cmd(int sock, FAR const char *ifname,
                          FAR const char *freqstr, FAR const char *flagstr);
static void wapi_essid_cmd(int sock, FAR const char *ifname,
                           FAR const char *essid, FAR const char *flagstr);
static void wapi_mode_cmd(int sock, FAR const char *ifname,
                          FAR const char *modestr);
static void wapi_ap_cmd(int sock, FAR const char *ifname,
                        FAR const char *macstr);
static void wapi_bitrate_cmd(int sock, FAR const char *ifname,
                             FAR const char *ratestr, FAR const char *flagstr);
static void wapi_txpower_cmd(int sock, FAR const char *ifname,
                             FAR const char *pwrstr, FAR const char *flagstr);
static void wapi_scan_cmd(int sock, FAR const char *ifname);

static void wapi_showusage(FAR const char *progname, int exitcode);

/****************************************************************************
 * Private Data
 ****************************************************************************/

static const struct wapi_command_s g_wapi_commands[] =
{
  {"help",    0, (CODE void *)NULL},
  {"show",    1, (CODE void *)wapi_show_cmd},
  {"scan",    1, (CODE void *)wapi_scan_cmd},
  {"ip",      2, (CODE void *)wapi_ip_cmd},
  {"mask",    2, (CODE void *)wapi_mask_cmd},
  {"freq",    3, (CODE void *)wapi_freq_cmd},
  {"essid",   3, (CODE void *)wapi_essid_cmd},
  {"mode",    2, (CODE void *)wapi_mode_cmd},
  {"ap",      2, (CODE void *)wapi_ap_cmd},
  {"bitrate", 3, (CODE void *)wapi_bitrate_cmd},
  {"txpower", 3, (CODE void *)wapi_txpower_cmd},
};

#define NCOMMANDS (sizeof(g_wapi_commands) / sizeof(struct wapi_command_s))

/****************************************************************************
 * Private Functions
 ****************************************************************************/

/****************************************************************************
 * Name: wapi_str2int
 *
 * Description:
 *   Convert a string to an integer value
 *
 ****************************************************************************/

static int wapi_str2int(FAR const char *str)
{
  FAR char *endptr;
  long value;

  value = strtol(str, &endptr, 0);
  if (*endptr != '\0')
    {
      WAPI_ERROR("ERROR: Garbage after numeric argument\n");
      exit(EXIT_FAILURE);
    }

  if (value > INT_MAX || value < INT_MIN)
    {
      WAPI_ERROR("ERROR: Integer value out of range\n");
      exit(EXIT_FAILURE);
    }

  return (int)value;
}

/****************************************************************************
 * Name: wapi_str2double
 *
 * Description:
 *   Convert a string to a double value
 *
 ****************************************************************************/

static double wapi_str2double(FAR const char *str)
{
  FAR char *endptr;
  double value;

  value = strtod(str, &endptr);
  if (*endptr != '\0')
    {
      WAPI_ERROR("ERROR: Garbage after numeric argument\n");
      exit(EXIT_FAILURE);
    }

  return value;
}

/****************************************************************************
 * Name: wapi_str2ndx
 *
 * Description:
 *   Return the index of a string in a list of strings
 *
 ****************************************************************************/

static unsigned int wapi_str2ndx(FAR const char *name, FAR const char **list,
                                 unsigned int listlen)
{
  unsigned int ndx;

  for (ndx = 0; ndx < listlen; ndx++)
    {
      if (strcmp(name, list[ndx]) == 0)
        {
          return ndx;
        }
    }

  WAPI_ERROR("ERROR: Invalid option string: %s\n", name);
  WAPI_ERROR("       Valid options include:\n");
  for (ndx = 0; ndx < listlen; ndx++)
    {
      WAPI_ERROR("       - %s\n", list[ndx]);
    }

  exit(EXIT_FAILURE);
}

/****************************************************************************
 * Name: wapi_show_cmd
 *
 * Description:
 *   Gets current configuration of the ifname using WAPI accessors and prints
 *   them in a pretty fashion with their corresponding return values. If a
 *   getter succeeds, we try to set that property with the same value to test
 *   the setters as well.
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_show_cmd(int sock, FAR const char *ifname)
{
  struct in_addr addr;

  double freq;
  enum wapi_freq_flag_e freq_flag;

  char essid[WAPI_ESSID_MAX_SIZE + 1];
  enum wapi_essid_flag_e essid_flag;

  enum wapi_mode_e mode;

  struct ether_addr ap;

  int bitrate;
  enum wapi_bitrate_flag_e bitrate_flag;

  int txpower;
  enum wapi_txpower_flag_e txpower_flag;

  int ret;

  printf("%s Configuration:\n", ifname);

  /* Get ip */

  bzero(&addr, sizeof(struct in_addr));
  ret = wapi_get_ip(sock, ifname, &addr);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_ip() failed: %d\n", ret);
    }
  else
    {
      printf("       IP: %s\n", inet_ntoa(addr));
    }

  /* Get netmask */

  bzero(&addr, sizeof(struct in_addr));
  ret = wapi_get_netmask(sock, ifname, &addr);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_netmask() failed: %d\n", ret);
    }
  else
    {
      printf("  NetMask: %s\n", inet_ntoa(addr));
    }

  /* Get frequency */

  ret = wapi_get_freq(sock, ifname, &freq, &freq_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_freq() failed: %d\n", ret);
    }
  else
    {
      double tmpfreq;
      int chan;

      printf("Frequency: %g\n", freq);
      printf("     Flag: %s\n", g_wapi_freq_flags[freq_flag]);

      ret = wapi_freq2chan(sock, ifname, freq, &chan);
      if (ret < 0)
        {
          WAPI_ERROR("ERROR: wapi_freq2chan() failed: %d\n", ret);
        }
      else
        {
          printf("  Channel: %d\n", chan);
        }

      ret = wapi_chan2freq(sock, ifname, chan, &tmpfreq);
      if (ret < 0)
        {
          WAPI_ERROR("ERROR: wapi_chan2freq() failed: %d\n", ret);
        }
      else
        {
          printf("Frequency: %g\n", tmpfreq);
        }
    }

  /* Get the ESSID */

  ret = wapi_get_essid(sock, ifname, essid, &essid_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_essid() failed: %d\n", ret);
    }
  else
    {
      printf("    ESSID: %s\n", essid);
      printf("     Flag: %s\n", g_wapi_essid_flags[essid_flag]);
    }

  /* Get operating mode */

  ret = wapi_get_mode(sock, ifname, &mode);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_mode() failed: %d\n", ret);
    }
  else
    {
      printf("     Mode: %s", g_wapi_modes[mode]);
    }

  /* Get AP */

  ret = wapi_get_ap(sock, ifname, &ap);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_ap() failed: %d\n", ret);
    }
  else
    {
      printf("       AP: %02x:%02x:%02x:%02x:%02x:%02x\n",
             ap.ether_addr_octet[0], ap.ether_addr_octet[1],
             ap.ether_addr_octet[2], ap.ether_addr_octet[3],
             ap.ether_addr_octet[4], ap.ether_addr_octet[5]);
    }

  /* Get bitrate */

  ret = wapi_get_bitrate(sock, ifname, &bitrate, &bitrate_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_bitrate() failed: %d\n", ret);
    }
  else
    {
      printf("  BitRate: %d\n", bitrate);
      printf("     Flag: %s\n", g_wapi_bitrate_flags[bitrate_flag]);
    }

  /* Get txpower */

  ret = wapi_get_txpower(sock, ifname, &txpower, &txpower_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_get_txpower() failed: %d\n", ret);
    }
  else
    {
      printf("  TxPower: %d\n", txpower);
      printf("     Flag: %s\n", g_wapi_txpower_flags[txpower_flag]);
    }
}

/****************************************************************************
 * Name: wapi_ip_cmd
 *
 * Description:
 *   Set the IP address.
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_ip_cmd(int sock, FAR const char *ifname,
                        FAR const char *addrstr)
{
  struct in_addr addr;
  int ret;

  /* Format the request */

  addr.s_addr = inet_addr(addrstr);

  /* Set the IP address */

  ret = wapi_set_ip(sock, ifname, &addr);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_set_ip() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_mask_cmd
 *
 * Description:
 *  Set the network mask
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_mask_cmd(int sock, FAR const char *ifname,
                          FAR const char *maskstr)
{
  struct in_addr addr;
  int ret;

  /* Format the request */

  addr.s_addr = inet_addr(maskstr);

  /* Set the network mask */

  ret = wapi_set_netmask(sock, ifname, &addr);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_set_netmask() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_freq_cmd
 *
 * Description:
 *  Set the frequency
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_freq_cmd(int sock, FAR const char *ifname,
                          FAR const char *freqstr, FAR const char *flagstr)
{
  double frequency;
  enum wapi_freq_flag_e freq_flag;
  int ret;

  /* Convert input strings to values */

  frequency = wapi_str2double(freqstr);
  freq_flag = (enum wapi_freq_flag_e)wapi_str2ndx(flagstr, g_wapi_freq_flags,
                                             IW_FREQ_NFLAGS);

  /* Set the frequency */

  ret = wapi_set_freq(sock, ifname, frequency, freq_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: \nwapi_set_freq() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_essid_cmd
 *
 * Description:
 *  Set the ESSID
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_essid_cmd(int sock, FAR const char *ifname,
                           FAR const char *essid, FAR const char *flagstr)
{
  enum wapi_essid_flag_e essid_flag;
  int ret;

  /* Convert input strings to values */

  essid_flag = (enum wapi_essid_flag_e)wapi_str2ndx(flagstr, g_wapi_essid_flags, 2);

  /* Set the ESSID */

  ret = wapi_set_essid(sock, ifname, essid, essid_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_set_essid() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_mode_cmd
 *
 * Description:
 *  Set the operating mode
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_mode_cmd(int sock, FAR const char *ifname,
                          FAR const char *modestr)
{
  enum wapi_mode_e mode;
  int ret;

  /* Convert input strings to values */

  mode = (enum wapi_mode_e)wapi_str2ndx(modestr, g_wapi_modes, IW_MODE_NFLAGS);

  /* Set operating mode */

  ret = wapi_set_mode(sock, ifname, mode);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: \nwapi_set_mode() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_ap_cmd
 *
 * Description:
 *  Set the AP
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_ap_cmd(int sock, FAR const char *ifname,
                        FAR const char *macstr)
{
  struct ether_addr ap;
  int ret;

  /* Convert input strings to values */

  sscanf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x",
         &ap.ether_addr_octet[0], &ap.ether_addr_octet[1],
         &ap.ether_addr_octet[2], &ap.ether_addr_octet[3],
         &ap.ether_addr_octet[4], &ap.ether_addr_octet[5]);

  /* Set ap */

  ret = wapi_set_ap(sock, ifname, &ap);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: \nwapi_set_ap() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_bitrate_cmd
 *
 * Description:
 *  Set the bit rate
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_bitrate_cmd(int sock, FAR const char *ifname,
                             FAR const char *ratestr, FAR const char *flagstr)

{
  enum wapi_bitrate_flag_e bitrate_flag;
  int bitrate;
  int ret;

  /* Convert input strings to values */

  bitrate      = wapi_str2int(ratestr);
  bitrate_flag = (enum wapi_bitrate_flag_e)
    wapi_str2ndx(flagstr, g_wapi_bitrate_flags, 2);

  /* Set bitrate */

  ret = wapi_set_bitrate(sock, ifname, bitrate, bitrate_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: \nwapi_set_bitrate() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_txpower_cmd
 *
 * Description:
 *  Set the TX power
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_txpower_cmd(int sock, FAR const char *ifname,
                             FAR const char *pwrstr, FAR const char *flagstr)
{
  enum wapi_txpower_flag_e txpower_flag;
  int txpower;
  int ret;

  /* Convert input strings to values */

  txpower      = wapi_str2int(pwrstr);
  txpower_flag = (enum wapi_txpower_flag_e)
    wapi_str2ndx(flagstr, g_wapi_txpower_flags, IW_TXPOW_NFLAGS);

  /* Set txpower */

  ret = wapi_set_txpower(sock, ifname, txpower, txpower_flag);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: \nwapi_set_txpower() failed: %d\n", ret);
    }
}

/****************************************************************************
 * Name: wapi_scan_cmd
 *
 * Description:
 *   Scans available APs in the range using given ifname interface.
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_scan_cmd(int sock, FAR const char *ifname)
{
  int sleepdur = 1;
  int sleeptries = 5;
  struct wapi_list_s list;
  FAR struct wapi_scan_info_s *info;
  int ret;

  /* Start scan */

  ret = wapi_scan_init(sock, ifname);
  WAPI_ERROR("ERROR: wapi_scan_init() failed: %d\n", ret);

  /* Wait for completion */

  do
    {
      sleep(sleepdur);
      ret = wapi_scan_stat(sock, ifname);
      WAPI_ERROR("ERROR: wapi_scan_stat() failed: %d, sleeptries: %d\n",
                 ret, sleeptries);
    }
  while (--sleeptries > 0 && ret > 0);

  if (ret < 0)
    {
      return;
    }

  /* Collect results */

  bzero(&list, sizeof(struct wapi_list_s));
  ret = wapi_scan_coll(sock, ifname, &list);
  if (ret < 0)
    {
      WAPI_ERROR("ERROR: wapi_scan_coll() failed: %d\n", ret);
    }

  /* Print found aps */

  for (info = list.head.scan; info; info = info->next)
    {
      printf("    %02x:%02x:%02x:%02x:%02x:%02x %s\n",
             info->ap.ether_addr_octet[0], info->ap.ether_addr_octet[1],
             info->ap.ether_addr_octet[2], info->ap.ether_addr_octet[3],
             info->ap.ether_addr_octet[4],  info->ap.ether_addr_octet[5],
             (info->has_essid ? info->essid : ""));
    }

  /* Free ap list */

  info = list.head.scan;
  while (info)
    {
      FAR struct wapi_scan_info_s *temp;

      temp = info->next;
      free(info);
      info = temp;
    }
}

/****************************************************************************
 * Name: wapi_showusage
 *
 * Description:
 *   Show program usage.
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

static void wapi_showusage(FAR const char *progname, int exitcode)
{
  int i;

  fprintf(stderr, "Usage: %s show <ifname>\n", progname);
  fprintf(stderr, "       %s scan <ifname>\n", progname);
  fprintf(stderr, "       %s ip <ifname> <IP address>\n", progname);
  fprintf(stderr, "       %s mask <ifname> <mask>\n", progname);
  fprintf(stderr, "       %s freq <ifname> <frequency> <flag>\n", progname);
  fprintf(stderr, "       %s essid <ifname> <essid> <flag>\n", progname);
  fprintf(stderr, "       %s mode <ifname> <ifname> <mode>\n", progname);
  fprintf(stderr, "       %s ap <ifname> <ifname> <MAC address>\n", progname);
  fprintf(stderr, "       %s bitrate <ifname> <bitrate> <flag>\n", progname);
  fprintf(stderr, "       %s txpower <ifname> <txpower> <flag>\n", progname);
  fprintf(stderr, "       %s help\n", progname);

  fprintf(stderr, "\nFrequency Flags:\n");
  for (i = 0; i < IW_FREQ_NFLAGS; i++)
    {
       fprintf(stderr, "       %s\n", g_wapi_freq_flags[i]);
    }

  fprintf(stderr, "\nESSID Flags:\n");
  for (i = 0; i < 2; i++)
    {
      fprintf(stderr, "       %s\n", g_wapi_essid_flags[i]);
    }

  fprintf(stderr, "\nOperating Modes:\n");
  for (i = 0; i < IW_MODE_NFLAGS; i++)
    {
      fprintf(stderr, "       %s\n", g_wapi_modes[i]);
    }

  fprintf(stderr, "\nBitrate Flags:\n");
  for (i = 0; i < 2; i++)
    {
      fprintf(stderr, "       %s\n", g_wapi_bitrate_flags[i]);
    }

  fprintf(stderr, "\nTX power Flags:\n");
  for (i = 0; i < IW_TXPOW_NFLAGS; i++)
    {
      fprintf(stderr, "       %s\n", g_wapi_txpower_flags[i]);
    }

  exit(exitcode);
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int wapi_main(int argc, char *argv[])
#endif
{
  FAR const char *cmdname;
  FAR const struct wapi_command_s *wapicmd;
  int sock;
  int i;

  /* Get the command */

  if (argc < 2)
    {
      WAPI_ERROR("ERROR: Missing command\n");
      wapi_showusage(argv[0], EXIT_FAILURE);
    }

  cmdname = argv[1];

  /* Find the command in the g_wapi_command[] list */

  wapicmd = NULL;
  for (i = 0; i < NCOMMANDS; i++)
    {
      FAR const struct wapi_command_s *cmd = &g_wapi_commands[i];
      if (strcmp(cmdname, cmd->name) == 0)
        {
          wapicmd = cmd;
          break;
        }
    }

  if (wapicmd == NULL)
    {
      WAPI_ERROR("ERROR: Unsupported command: %s\n", cmdname);
      wapi_showusage(argv[0], EXIT_FAILURE);
    }

  if (wapicmd->noptions + 2 < argc)
    {
      WAPI_ERROR("ERROR: Garbage at end of command ignored\n");
    }
  else if (wapicmd->noptions + 2 > argc)
    {
      WAPI_ERROR("ERROR: Missing required command options: %s\n",
                 cmdname);
      wapi_showusage(argv[0], EXIT_FAILURE);
    }

  /* Special case the help command which has no arguments, no handler,
   * and does not need a socket.
   */

  if (wapicmd->handler == NULL)
    {
      wapi_showusage(argv[0], EXIT_SUCCESS);
    }

  /* Create a communication socket */

  sock = wapi_make_socket();
  if (sock < 0)
    {
      WAPI_ERROR("ERROR: wapi_make_socket() failed: %d\n", sock);
      return EXIT_FAILURE;
    }

  /* Dispatch the command handling */

  switch (wapicmd->noptions)
    {
      default:
      case 0:
        WAPI_ERROR("ERROR: Internal craziness\n");
        wapi_showusage(argv[0], EXIT_FAILURE);

      case 1:
        ((cmd1_t)wapicmd->handler)(sock, argv[2]);
        break;

      case 2:
        ((cmd2_t)wapicmd->handler)(sock, argv[2], argv[3]);
        break;

      case 3:
        ((cmd3_t)wapicmd->handler)(sock, argv[2], argv[3], argv[4]);
        break;
    }

  /* Close communication socket */

  close(sock);
  return EXIT_SUCCESS;
}
