#ifndef __ip6_h
#define __ip6_h

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#include "mem.h"
#include "str.h"

#ifndef IP_LEN
#define IP_LEN	16
#endif

static int inline ipv6_null(unsigned char *ip)
{
	int i;
	for (i = 0; ip[i] == 0 && i < 16; i++);
	return i == 16 ? 1 : 0;
}
static int inline ipv6_helper(const char *str, unsigned char ip[16], unsigned char *sub)
{
	register int p, v, v4, v6, n;
	int x[8];
	int c, s, d, saw_colon;

	/* and you thought ipv4 was bad... */
	saw_colon = 0;
	for (p = s = d = v4 = v6 = n = 0, c = -1; p < 8 && *str; str++) {
		switch (*str) {
		case '0':		v = 0; break;
		case '1':		v = 1; break;
		case '2':		v = 2; break;
		case '3':		v = 3; break;
		case '4':		v = 4; break;
		case '5':		v = 5; break;
		case '6':		v = 6; break;
		case '7':		v = 7; break;
		case '8':		v = 8; break;
		case '9':		v = 9; break;
		case 'a': case 'A':	v = 10; break;
		case 'b': case 'B':	v = 11; break;
		case 'c': case 'C':	v = 12; break;
		case 'd': case 'D':	v = 13; break;
		case 'e': case 'E':	v = 14; break;
		case 'f': case 'F':	v = 15; break;
		case '/':
			/* cidr */
			if (!sub) return 0;
			s = 1;
			if (d) {
				x[p] = v4;
			} else {
				x[p] = v6;
			}
			p++; v4 = v6 = n = 0;
			break;
		case ':':
			if (s || d) return 0;
			saw_colon = 1;
			x[p] = v6; p++; v4 = v6 = n = 0;
			if (str[1] == ':') {
				c = p;
				str++;
			}
			break;

		case '.':
			if (s) return 0;
			x[p] = v4; p++; v4 = v6 = n = 0;
			d = 1;
			break;
		default:
			return 0;
		};
		v4 *= 10; v4 += v;
		v6 *= 16; v6 += v;
		n++;
	}
	if (!saw_colon) {
		/* could be ipv4... */
		return 0;
	}
	if (n) {
		if (s) {
			if (!sub) return 0;

			/* last atom was subnet */
			if (v4 < 0 || v4 > 128) return 0;

			/* invert */
			v4 = 128 - v4;
			for (v6 = v = 0; v6 < 16; v += 8, v6++) {
				if (v4 < v) {
					sub[v6] = (0xFF << v4) & 0xFF;
				} else {
					sub[v6] = 0xFF;
				}
			}

		} else if (d) {
			x[p] = v4;
			p++;
		} else {
			x[p] = v6;
			p++;
		}
	}

	for (v = v4 = 0; v < c; v++, v4++, v4++) {
		ip[v4] = (x[v] & 0xFF00) >> 8;
		ip[v4+1] = (x[v] & 0x00FF);
	}
	v6 = (16 - p) + v4;
	if (!sub && v6 != 0 && c == -1)
		return 0;
	for (; v4 < v6; v4++)
		ip[v4] = 0;
	for (v = (c == -1 ? 0 : c); v < p; v++, v4++, v4++) {
		ip[v4] = (x[v] & 0xFF00) >> 8;
		ip[v4+1] = (x[v] & 0x00FF);
	}
	for (; v4 < 32; v4++) {
		ip[v4] = 0; /* set the rest of the bits to 0 */
	}
	return 1;
}
static int inline ipv6_scan(const char *str, unsigned char ip[16])
{
	return ipv6_helper(str, ip, 0) ? 16 : 0;
}
static int inline ipv6_cidr(const char *str, unsigned char ip[32])
{
	return ipv6_helper(str, ip, ip+16) ? 32 : 0;
}
static int inline ipv6_in_subnet(unsigned char cidr[32], unsigned char ip[16])
{
	register int i;
	for (i = 0; i < 16 && cidr[i] == 0; i++);
	if (i == 16) return 1;
	for (i = 0; i < 16; i++) {
		if (cidr[i] != (ip[i] & cidr[16+i]))
			return 0;
	}
	return 1;
}
static int inline socket_bind6(int fd, unsigned char ip[16], int port)
{
	struct sockaddr_in6 sin;

	memzero(&sin, sizeof(sin));

	sin.sin6_family = PF_INET6;
	sin.sin6_port = htons(port);
	memcpy(&sin.sin6_addr, ip, 16);

	return bind(fd, (struct sockaddr *)&sin, sizeof(sin));
}
static int inline socket_bind6_reuse(int fd, unsigned char ip[16], int port)
{
	int opt = 1;
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	return socket_bind6(fd, ip, port);
}
static int inline socket_peer6(int fd, unsigned char ip[16], int *port)
{
	struct sockaddr_in6 sin;
	int silen;

	memzero(&sin, sizeof(sin));

	silen = sizeof(sin);
	sin.sin6_family = PF_INET6;
	if (getpeername(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) {
		return 0;
	}

	if (sin.sin6_family != PF_INET6)
		return 0;

	/* Clib */
	memcpy(ip, &sin.sin6_addr, 16);
	*port = ntohs(sin.sin6_port);
	return 1;
}

static int inline socket_local6(int fd, unsigned char ip[16], int *port)
{
	struct sockaddr_in6 sin;
	int silen;

	memzero(&sin, sizeof(sin));

	silen = sizeof(sin);
	sin.sin6_family = PF_INET6;
	if (getsockname(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) {
		return 0;
	}

	if (sin.sin6_family != PF_INET6)
		return 0;

	/* Clib */
	memcpy(ip, &sin.sin6_addr, 16);
	*port = ntohs(sin.sin6_port);
	return 1;
}

static int inline socket_tcp6(void)
{
	int fd;

	fd = socket(PF_INET6, SOCK_STREAM, 0);
	if (fd == -1) return -1;
	if (ndelay_on(fd) == -1) { close(fd); return -1; }
	return fd;
}
static int inline socket_udp6(void)
{
	int fd;

	fd = socket(PF_INET6, SOCK_DGRAM, 0);
	if (fd == -1) return -1;
	if (ndelay_on(fd) == -1) { close(fd); return -1; }
	return fd;
}
static int inline socket_accept6(int s, unsigned char ip[16], int *port)
{
	struct sockaddr_in6 sa;
	int dummy = sizeof sa;
	int r;

	memzero(&sa, sizeof(sa));
	r = accept(s, (struct sockaddr *)&sa, &dummy);
	if (r == -1) return -1;

	/* Clib */
	memcpy(ip, &sa.sin6_addr, 16);
	*port = ntohs(sa.sin6_port);

	return r;
}
static int inline socket_recv6(int s, char *buf, int len, unsigned char ip[16], int *port)
{
	struct sockaddr_in6 sa;
	int dummy = sizeof sa;
	int r;

	memzero(&sa, sizeof(sa));
	r = recvfrom(s, buf, len, 0, (struct sockaddr *)&sa, &dummy);
	if (r == -1) return -1;

	/* Clib */
	memcpy(ip, &sa.sin6_addr, 16);
	*port = ntohs(sa.sin6_port);

	return r;
}
static int inline socket_send6(int s, const char *buf, int len, const unsigned char ip[16], int port)
{
	struct sockaddr_in6 sa;

	memzero(&sa, sizeof(sa));
	sa.sin6_family = PF_INET6;
	/* Clib */
	sa.sin6_port = htons(port);
	memcpy(&sa.sin6_addr, ip, 16);

	return sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa));
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1