/*
 * General utility functions for udp tunnel
 */
/*
 * Copyright 1996-2013 Ian Jackson <ijackson@chiark.greenend.org.uk>
 * Copyright 1998 David Damerell <damerell@chiark.greenend.org.uk>
 * Copyright 1999,2003
 *    Chancellor Masters and Scholars of the University of Cambridge
 * Copyright 2010 Tony Finch <fanf@dotat.at>
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with userv-utils; if not, see http://www.gnu.org/licenses/.
 */

#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

#include "forwarder.h"

const char *const *argv;
char programid[SYS_NMLN+sizeof(PROGRAM)+3];

void arg_assert_fail(const char *msg) {
  fprintf(stderr, PROGRAM ": argument error (!`%s')\n",msg);
  exit(12);
}

void sysfail(const char *msg) {
  fprintf(stderr, "%s: fatal system error: %s: %s\n", programid, msg, strerror(errno));
  exit(8);
}

void fail(const char *msg) {
  fprintf(stderr, "%s: fatal error: %s\n", programid, msg);
  exit(4);
}

void sysdiag(const char *msg) {
  fprintf(stderr, "%s: system/network error: %s: %s\n", programid, msg, strerror(errno));
}

void diag(const char *msg) {
  fprintf(stderr, "%s: %s\n", programid, msg);
}

time_t now(void) {
  time_t r;
  if (time(&r) == (time_t)-1) sysfail("get time of day");
  return r;
}

void *xmalloc(size_t sz) {
  void *r;
  r= malloc(sz);
  if (!r) sysfail("allocate memory");
  return r;
}

void write_must(int fd, const void *p_in, int sz, const char *what) {
  const unsigned char *p= p_in;
  int r;
  
  while (sz) {
    r= write(fd,p,sz);
    if (r<0) {
      if (errno == EINTR) continue;
      else sysfail(what);
    }
    assert(r && r <= sz);
    p += r;
    sz -= r;
  }
}

void read_must(int fd, void *p_in, int sz, const char *what) {
  unsigned char *p= p_in;
  int r;
  
  while (sz) {
    r= read(fd,p,sz);
    if (r<0) {
      if (errno == EINTR) continue;
      else sysfail(what);
    }
    if (r==0) fail(what);
    assert(r <= sz);
    p += r;
    sz -= r;
  }
}

const char *getarg_string(void) {
  const char *arg;
  
  arg= *++argv;
  arg_assert(arg);
  return arg;
}

unsigned long getarg_ulong(void) {
  char *ep;
  unsigned long ul;
  
  ul= strtoul(getarg_string(),&ep,0);
  arg_assert(!*ep);
  return ul;
}

void *buf_append(struct buffer *buf, size_t amount) {
  void *p;

  p= buf->start + buf->size;
  buf->size += amount;
  return p;
}
  
void *buf_prepend(struct buffer *buf, size_t amount) {
  buf->size += amount;
  return buf->start -= amount;
}

void *buf_unappend(struct buffer *buf, size_t amount) {
  if (buf->size < amount) return 0;
  return buf->start + (buf->size -= amount);
}

void *buf_unprepend(struct buffer *buf, size_t amount) {
  void *p;

  p= buf->start;
  buf->start += amount;
  buf->size -= amount;
  return p;
}
