<commit_before>/*
 * Copyright (c) 2017 <NAME>
 * http://github.com/devaos/node-icmp-ping/blob/master/LICENSE
 *
 * Based on ping.c by <NAME>
 *  U.S. Army Ballistic Research Laboratory
 *  December, 1983
 */

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <uv.h>
#include "ping.h"

/* ========================================================================== */

extern int errno;
static int instances = 0;
ping_options_t ping_default_options = {NULL, 5, 6000, 1000, NULL, NULL, NULL, NULL};

/* ========================================================================== */
/*
static void WorkAsync(uv_work_t *req) {
  printf("WTF9?\n");
  //ping_state_t* context = (ping_state_t*)req->data;
  //uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  printf("WTF10?\n");
}

static void WorkAsyncComplete(uv_work_t *req, int status) {
  printf("WTF11?\n");
}
*/
ping_state_t* ping(const char *target, ping_options_t *options) {
  int rc;
  ping_state_t *context = calloc(1, sizeof(ping_state_t));
  uv_getaddrinfo_t *resolver = NULL;

  if (!context) {
    if (options && options->cb_complete) {
      options->cb_complete(NULL, 0);
    }
    return NULL;
  }

  resolver = malloc(sizeof(uv_getaddrinfo_t));
  context->hints = malloc(sizeof(struct addrinfo));
  context->options = malloc(sizeof(ping_options_t));

  if (!resolver || !context->hints || !context->options) {
    context->err = -1;
    snprintf(context->errmsg, MAXERRMSG, "calloc() failure [%d]\n", errno);
    if (resolver) {
      free(resolver);
    }
    cleanup(context);
    return NULL;
  }

  if (options) {
    context->options = memcpy(context->options, options, sizeof(ping_options_t));
  } else {
    context->options = memcpy(context->options, &ping_default_options, sizeof(ping_options_t));
  }

  gettimeofday(&context->started, NULL);
  context->pid = getpid() & 0xFFFF;
  context->instance = ++instances;
  strncpy(context->target, target, sizeof(context->target)-1);
  context->osize = 64;
  context->tmin = 999999999;
  context->loop_handle = uv_default_loop();

  context->hints->ai_family = AF_INET;
  context->hints->ai_socktype = SOCK_RAW;
  context->hints->ai_protocol = IPPROTO_ICMP;
  context->hints->ai_flags = 0;

  resolver->data = context;

  rc = uv_getaddrinfo(context->loop_handle, resolver, on_target_resolved, context->target, NULL, context->hints);

  if (rc) {
    context->err = -1;
    snprintf(context->errmsg, MAXERRMSG, "uv_getaddrinfo() failure [%s]", uv_err_name(rc));
    cleanup(context);
    return NULL;
  }

  return context;
}

/* ========================================================================== */

void cleanup(ping_state_t *context) {
  int runtime;
  struct timeval tv;

  if (context->socket) {
    close(context->socket);
    context->socket = 0;
    uv_poll_stop(&context->poll_handle);
    uv_timer_stop(&context->interval_handle);
    uv_timer_stop(&context->timeout_handle);
  }

  gettimeofday(&context->ended, NULL);
  memcpy(&tv, &context->ended, sizeof(tv));
  tvsubtract(&tv, &context->started);
  runtime = tv.tv_sec * 1000 + (tv.tv_usec / 1000);

  if (context->options->cb_complete) {
    context->options->cb_complete(context, runtime);
  }

  if (context->to) {
    uv_freeaddrinfo(context->to);
    context->to = NULL;
  }

  if (context->hints) {
    free(context->hints);
    context->hints = NULL;
  }

  if (context->options) {
    free(context->options);
    context->options = NULL;
  }

  free(context);
}

/* ========================================================================== */

void on_target_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) {
  ping_state_t *context = (ping_state_t *)resolver->data;
  free(resolver);

  if (status < 0) {
    context->err = -1;
    snprintf(context->errmsg, MAXERRMSG, "uv_getaddrinfo() failure [%s]", uv_err_name(status));
    cleanup(context);
    return;
  }

  context->to = res;
  uv_ip4_name((struct sockaddr_in*) res->ai_addr, context->toip, 16);
  begin_probing(context);
}

/* ========================================================================== */

void begin_probing(ping_state_t *context) {
  int rc, on = 1;
  struct addrinfo *p;

  if (getuid() != 0) {
    context->err = -1;
    strcpy(context->errmsg, "implementation failure [Raw sockets for ICMP require root]");
    cleanup(context);
    return;
  }

  for (p = context->to; p; p = p->ai_next) {
    context->socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
    if (context->socket == -1)
      continue;
    break;
  }

  if (!p) {
    context->socket = 0;<commit_msg>Removing root requirement as `setcap cap_net_raw+p /path/to/bin` facilitates unprivileged users being able to work with raw / icmp sockets<commit_after>/*
 * Copyright (c) 2017 <NAME>
 * http://github.com/devaos/node-icmp-ping/blob/master/LICENSE
 *
 * Based on ping.c by <NAME>
 *  U.S. Army Ballistic Research Laboratory
 *  December, 1983
 */

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <uv.h>
#include "ping.h"

/* ========================================================================== */

extern int errno;
static int instances = 0;
ping_options_t ping_default_options = {NULL, 5, 6000, 1000, NULL, NULL, NULL, NULL};

/* ========================================================================== */
/*
static void WorkAsync(uv_work_t *req) {
  printf("WTF9?\n");
  //ping_state_t* context = (ping_state_t*)req->data;
  //uv_run(uv_default_loop(), UV_RUN_DEFAULT);
  printf("WTF10?\n");
}

static void WorkAsyncComplete(uv_work_t *req, int status) {
  printf("WTF11?\n");
}
*/
ping_state_t* ping(const char *target, ping_options_t *options) {
  int rc;
  ping_state_t *context = calloc(1, sizeof(ping_state_t));
  uv_getaddrinfo_t *resolver = NULL;

  if (!context) {
    if (options && options->cb_complete) {
      options->cb_complete(NULL, 0);
    }
    return NULL;
  }

  resolver = malloc(sizeof(uv_getaddrinfo_t));
  context->hints = malloc(sizeof(struct addrinfo));
  context->options = malloc(sizeof(ping_options_t));

  if (!resolver || !context->hints || !context->options) {
    context->err = -1;
    snprintf(context->errmsg, MAXERRMSG, "calloc() failure [%d]\n", errno);
    if (resolver) {
      free(resolver);
    }
    cleanup(context);
    return NULL;
  }

  if (options) {
    context->options = memcpy(context->options, options, sizeof(ping_options_t));
  } else {
    context->options = memcpy(context->options, &ping_default_options, sizeof(ping_options_t));
  }

  gettimeofday(&context->started, NULL);
  context->pid = getpid() & 0xFFFF;
  context->instance = ++instances;
  strncpy(context->target, target, sizeof(context->target)-1);
  context->osize = 64;
  context->tmin = 999999999;
  context->loop_handle = uv_default_loop();

  context->hints->ai_family = AF_INET;
  context->hints->ai_socktype = SOCK_RAW;
  context->hints->ai_protocol = IPPROTO_ICMP;
  context->hints->ai_flags = 0;

  resolver->data = context;

  rc = uv_getaddrinfo(context->loop_handle, resolver, on_target_resolved, context->target, NULL, context->hints);

  if (rc) {
    context->err = -1;
    snprintf(context->errmsg, MAXERRMSG, "uv_getaddrinfo() failure [%s]", uv_err_name(rc));
    cleanup(context);
    return NULL;
  }

  return context;
}

/* ========================================================================== */

void cleanup(ping_state_t *context) {
  int runtime;
  struct timeval tv;

  if (context->socket) {
    close(context->socket);
    context->socket = 0;
    uv_poll_stop(&context->poll_handle);
    uv_timer_stop(&context->interval_handle);
    uv_timer_stop(&context->timeout_handle);
  }

  gettimeofday(&context->ended, NULL);
  memcpy(&tv, &context->ended, sizeof(tv));
  tvsubtract(&tv, &context->started);
  runtime = tv.tv_sec * 1000 + (tv.tv_usec / 1000);

  if (context->options->cb_complete) {
    context->options->cb_complete(context, runtime);
  }

  if (context->to) {
    uv_freeaddrinfo(context->to);
    context->to = NULL;
  }

  if (context->hints) {
    free(context->hints);
    context->hints = NULL;
  }

  if (context->options) {
    free(context->options);
    context->options = NULL;
  }

  free(context);
}

/* ========================================================================== */

void on_target_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) {
  ping_state_t *context = (ping_state_t *)resolver->data;
  free(resolver);

  if (status < 0) {
    context->err = -1;
    snprintf(context->errmsg, MAXERRMSG, "uv_getaddrinfo() failure [%s]", uv_err_name(status));
    cleanup(context);
    return;
  }

  context->to = res;
  uv_ip4_name((struct sockaddr_in*) res->ai_addr, context->toip, 16);
  begin_probing(context);
}

/* ========================================================================== */

void begin_probing(ping_state_t *context) {
  int rc, on = 1;
  struct addrinfo *p;

  for (p = context->to; p; p = p->ai_next) {
    context->socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
    if (context->socket == -1)
      continue;
    break;
  }

  if (!p) {
    context->socket = 0;
{'fraction_non_alphanumeric': 0.22965464647565095, 'fraction_numerical': 0.012855430874822965, 'mean_word_length': 4.266781411359725, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 161, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2910061', 'n_tokens_mistral': 3287, 'n_tokens_neox': 3044, 'n_words': 600}