#include "ipxtund.h"

#define ERRORDEST(a,b) (a&b)

static char *gettime(void);

void errormsg(const int destmask, const char *upname, const char *fmt, ...)
{
  va_list ap;
  int saved_errno;
  size_t len;
  char c, *cp1, *cp2, str[STRLEN+1], fmt_cpy[STRLEN+1], upstr[S_STRLEN];
  
  saved_errno = errno;

  va_start(ap, fmt);
  for (cp1=fmt_cpy; (c=*fmt)!='\0'; ++fmt) {
    if (c=='%' && fmt[1]=='m') {
      ++fmt;
      for (cp2=strerror(saved_errno); (*cp1=*cp2++)!='\0'; ++cp1);
    }
    else {
      *cp1++ = c;
    }
  }
  *cp1 = '\0';
  vsprintf(str,fmt_cpy,ap);
  len = strlen(str) - 1;
  if (str[len++]!='\n') {
    str[len++] = '\n';
    str[len] = '\0';
  }
  va_end(ap);
  if (upname != NULL) {
    sprintf(upstr,"(%s): ",upname);
  }
  else {
    upstr[0] = '\0';
  }
  if (ERRORDEST(E_STDERR,destmask)) {
      fprintf(stderr,"%s",str);
  }
  if (ERRORDEST(E_LOG,destmask)) {
    fprintf(log_fp,"%.15s %s[%ld]: %s",gettime()+4*sizeof(char),
            upstr,(long)getpid(),str);
    fflush(log_fp);
  }
  
  errno = saved_errno;
  return;
}


void log(const char *fmt, ...)
{
  size_t len;
  va_list ap;
  char str[STRLEN+1];

  va_start(ap, fmt);
  vsprintf(str,fmt,ap);
  len = strlen(str) - 1;
  if (str[len++]!='\n') {
    str[len++] = '\n';
    str[len] = '\0';
  }
  fprintf(log_fp,"%.15s %s", gettime()+4*sizeof(char), str);
  va_end(ap);
  fflush(log_fp);
}


void log_configuration(const struct Config *config)
{
  int n;
  
  fprintf(log_fp,"Configuration:\n");
  if (config->local.server_name[0] == '\0') {
    fprintf(log_fp,"  Server: none\n");
  }
  else {
    fprintf(log_fp,"  Server: %s (ID: %s)\n",
            config->local.server_name, config->local.hostid);
  }
  fprintf(log_fp,"  Local:  UDP: %u  Ctrl: %u  TCP (listen): %u\n",
          config->local.udp_port, config->local.ctrl_port,
	  config->local.tcp.tcp_listen_port);
  if (config->local.tcp.tcp_listen_port == 0) {
    fprintf(log_fp,"        TCP disabled\n");
  }
  fprintf(log_fp,"  Routers:\n");
  for (n = 0; n < config->router_anz; n++) {
    fprintf(log_fp,"    %s  (UDP: %u  Ctrl: %u  TCP: %u)\n",
            config->router[n].name, config->router[n].udp_port,
	    config->router[n].ctrl_port, config->router[n].tcp_port);
    if (config->router[n].tcp_port == 0) {
      fprintf(log_fp,"      TCP disabled\n");
    }
    if (config->router[n].ping.roundtrip_time > 0) {
      fprintf(log_fp,"      Ping roundtrip time was %lu\n",
              config->router[n].ping.roundtrip_time);
    }
    fprintf(log_fp,"      Frametype (sending direction): ");
    log_frametypes(config->router[n].s_frametype);
    fprintf(log_fp,"\n");
    fprintf(log_fp,"      Frametypes (receiving direction):");
    log_frametypes(config->local.r_frametypes);
    fprintf(log_fp,"\n");
  }
  fprintf(log_fp,"  Interfaces:\n");
  for (n = 0; n < config->ether_anz; n++) {
    fprintf(log_fp,"    Name: %s\n", config->ether[n].name);
    fprintf(log_fp,"      MAC: ");
    fprint_as_hex_nl(log_fp, config->ether[n].mac, 6);
    fprintf(log_fp,"      Frametype (sending direction): ");
    log_frametypes(config->ether[n].s_frametype);
    fprintf(log_fp,"\n");
    fprintf(log_fp,"      Frametypes (receiving direction):");
    log_frametypes(config->ether[n].r_frametypes);
    fprintf(log_fp,"\n");
  }
  fprintf(log_fp,"\n\n");
}


void log_frametypes(const u_int frametypes)
{
  if (frametypes & ETHER_II) {
    fprintf(log_fp," Ether_II");
  }
  if (frametypes & ETHER_802_2) {
    fprintf(log_fp," Ether_802.2");
  }
  if (frametypes & ETHER_802_3) {
    fprintf(log_fp," Ether_802.3");
  }
  if (frametypes & ETHER_SNAP) {
    fprintf(log_fp," Ether_SNAP");
  }
  if (frametypes & ETHER_TRANS) {
    fprintf(log_fp," transparent");
  }
  if (frametypes & ETHER_AUTO) {
    fprintf(log_fp," automatic");
  }
  if (frametypes & ETHER_NONE) {
    fprintf(log_fp," none");
  }
}


void log_statistics(const time_t ti, const struct Ether ether_array[],
                    const int ether_anz, const struct Router router_array[],
		    const int router_anz, const struct Local *local)
{
  int k;
  const struct Ether *e;
  const struct Router *r;
  
  fprintf(log_fp,"\nSTATISTICS:\n");
  fprintf(log_fp,"packet transfer for %ld secounds\n", ti);
  if (ti == 0) {
    return;
  }
  for (k = 0; k < ether_anz; k++) {
    e = &ether_array[k];
    fprintf(log_fp,"\nEther %s:\n", e->name);
    fprintf(log_fp,"%lu bytes read (%lu bytes / sec)\n", e->stat.bytes_r,
            e->stat.bytes_r / ti);
    fprintf(log_fp,"%u packets successfully read\n", e->stat.packets_r);
    fprintf(log_fp,"largest packet read: %lu\n", e->stat.max_bytes_r);
    fprintf(log_fp,"%lu bytes sent (%lu bytes / sec)\n", e->stat.bytes_s,
            e->stat.bytes_s / ti);
    fprintf(log_fp,"largest packet sent: %lu\n", e->stat.max_bytes_s);
    fprintf(log_fp,"%u packets successfully written\n", e->stat.packets_s);
    if (e->stat.errors_r > 0 || e->stat.errors_s > 0) {
      fprintf(log_fp,"wrong packets read: %u\n", e->stat.errors_r);
      fprintf(log_fp,"wrong packets written: %u\n", e->stat.errors_s);
    }
  }

  for (k = 0; k < router_anz; k++) {
    r = &router_array[k];
    fprintf(log_fp,"\nRouter %s:\n", r->name);
    fprintf(log_fp,"%lu bytes read (%lu bytes / sec)\n", r->stat.bytes_r,
            r->stat.bytes_r / ti);
    fprintf(log_fp,"largest packet read: %lu\n", r->stat.max_bytes_r);
    fprintf(log_fp,"%u packets successfully read\n", r->stat.packets_r);
    fprintf(log_fp,"%lu bytes sent (%lu bytes / sec)\n", r->stat.bytes_s,
            r->stat.bytes_s / ti);
    fprintf(log_fp,"largest packet sent: %lu\n", r->stat.max_bytes_s);
    fprintf(log_fp,"%u packets successfully written\n", r->stat.packets_s);
    if (r->stat.errors_r > 0 || r->stat.errors_r > 0) {
      fprintf(log_fp,"wrong packets read: %u\n", r->stat.errors_r);
      fprintf(log_fp,"wrong packets written: %u\n", r->stat.errors_s);
    }
  }

  fprintf(log_fp,"\nUDP:\n");
  fprintf(log_fp,"%lu bytes read (%lu bytes / sec)\n", local->stat.bytes_r,
	  local->stat.bytes_r / ti);
  fprintf(log_fp,"largest packet read: %lu\n", local->stat.max_bytes_r);
  fprintf(log_fp,"%u packets successfully read\n", local->stat.packets_r);
  fprintf(log_fp,"%lu bytes sent (%lu bytes / sec)\n", local->stat.bytes_s,
	  local->stat.bytes_s / ti);
  fprintf(log_fp,"largest packet sent: %lu\n", local->stat.max_bytes_s);
  fprintf(log_fp,"%u packets successfully written\n", local->stat.packets_s);
  if (local->stat.errors_r > 0 || local->stat.errors_r > 0) {
    fprintf(log_fp,"wrong packets read: %u\n", local->stat.errors_r);
    fprintf(log_fp,"wrong packets written: %u\n", local->stat.errors_s);
  }
}


void log_ether_header(const u_char *ether_packet)
{
  fprintf(log_fp,"EtherDestination: ");
  fprint_as_hex_nl(log_fp, ether_packet, 6);
  fprintf(log_fp,"EtherSource: ");
  fprint_as_hex_nl(log_fp, &ether_packet[6], 6);
  fprintf(log_fp,"EtherType: 0x");
  fprint_as_hex_nl(log_fp, &ether_packet[12], 2);
}


void log_ipx_header(const u_char *ipx_packet)
{
  fprintf(log_fp,"IPX Checksum: 0x %2x %2x\n", (u_char)ipx_packet[0],
          (u_char)ipx_packet[1]);
  fprintf(log_fp,"IPX Length: %u\n", get_ipx_length(ipx_packet));
  fprintf(log_fp,"IPX Control: %u\n", ipx_packet[4]);
  fprintf(log_fp,"IPX Type: 0x%x\n", ipx_packet[5]);
  fprintf(log_fp,"IPX Destination Network: ");
  fprint_as_hex_nl(log_fp, &ipx_packet[6], 4);
  fprintf(log_fp,"IPX Destination Node: ");
  fprint_as_hex_nl(log_fp, &ipx_packet[10], 6);
  fprintf(log_fp,"IPX Destination Socket: ");
  fprint_as_hex_nl(log_fp, &ipx_packet[16], 2);
  fprintf(log_fp,"IPX Source Network: ");
  fprint_as_hex_nl(log_fp, &ipx_packet[18], 4);
  fprintf(log_fp,"IPX Source Node: ");
  fprint_as_hex_nl(log_fp, &ipx_packet[22], 6);
  fprintf(log_fp,"IPX Source Socket: ");
  fprint_as_hex_nl(log_fp, &ipx_packet[28], 2);
}


void log_ipx_packet(const struct Data_packet *packet)
{
  int k, n;
  const u_char *cp;
  
  cp = packet->data;
  fprintf(log_fp,"IPX data (%d bytes):\n", packet->len);
  n = 0;
  for (k=0; k < packet->len; k++) {
    fprintf(log_fp,"%x ", *cp);
    cp++;
    n++;
    if (n == 20) {
      fprintf(log_fp,"\n");
      n = 0;
    }
  }
  fprintf(log_fp,"\n");
}


int fprint_as_hex(FILE *fp, const char *bytes, const size_t len)
{
  size_t k;
  const u_char *ucp;
  
  for (k = 0, ucp = (u_char *)bytes; k < len; k++) {
    fprintf(fp,"%x ", *ucp++);
  }
  return 0;
}


int fprint_as_hex_nl(FILE *fp, const char *bytes, const size_t len)
{
  fprint_as_hex(fp, bytes, len);
  fprintf(fp,"\n");
  return 0;
}


void printifverbose(const char *fmt, ...)
{
  va_list ap;
  char str[STRLEN+1];

  if (! verbose) {
    return;
  }
  va_start(ap, fmt);
  vsprintf(str,fmt,ap);
  fprintf(stderr, str);
  va_end(ap);
}


void clear_stat(struct Stat *stat)
{
  stat->bytes_r = 0;
  stat->max_bytes_r = 0;
  stat->packets_r = 0;
  stat->errors_r = 0;
  stat->bytes_s = 0;
  stat->max_bytes_s = 0;
  stat->packets_s = 0;
  stat->errors_s = 0;
}


static char *gettime()
{
  time_t clock;
  static char str[ASCIITIMESTRLEN];
  
  clock = time((time_t)0);
  strcpy(str,asctime(localtime(&clock)));
  str[24] = '\0';
  return str;
}

