/* these functions are useful for dealing with IPv4 */
#ifndef __ip4_h
#define __ip4_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 <fcntl.h>

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

#ifndef IP_LEN
#define IP_LEN	4
#endif

static int inline ipv4_null(unsigned char *ip)
{
	int i;
	for (i = 0; ip[i] == 0 && i < 4; i++);
	return i == 4 ? 1 : 0;
}
static int inline ipv4_scan(const char *str, unsigned char ip[4])
{
	int p, v;

	ip[0] = ip[1] = ip[2] = ip[3] = 0;
	for (p = v = 0; *str && p < 4;) {
		switch (*str) {
		case '0': v *= 10; break;
		case '1': v *= 10; v ++; break;
		case '2': v *= 10; v += 2; break;
		case '3': v *= 10; v += 3; break;
		case '4': v *= 10; v += 4; break;
		case '5': v *= 10; v += 5; break;
		case '6': v *= 10; v += 6; break;
		case '7': v *= 10; v += 7; break;
		case '8': v *= 10; v += 8; break;
		case '9': v *= 10; v += 9; break;
		case '.': ip[p] = v; v = 0; p++; break;
		default: return 0;
		};
		str++;
	}
	if (p == 4) return 0;
	ip[p] = v;
	return 4;
}
static int inline ipv4_in_subnet(unsigned char cidr[8], unsigned char ip[4])
{
	register int i;
	if (ipv4_null(cidr)) return 1;
	for (i = 0; i < 4; i++) {
		if (cidr[i] != (ip[i] & cidr[4+i]))
			return 0;
	}
	return 1;
}
static int inline ipv4_cidr(char *str, unsigned char cidr[8])
{
	int r;
	str_t s;
	char *p;

	/* like ipv4_scan but parses a CIDR number */
	str_init(s);
	str_copy(s, str);
	for (p = str(s); *p && *p != '/'; p++);
	if (*p == '/') {
		*p = 0; p++;
		if (!ipv4_scan(str(s), cidr)) {
			mem_free(str(s));
			return 0;
		}
		for (r = 0; p[r]; r++)
			if (p[r] == '.' && ipv4_scan(p, cidr+4)) {
				/* form of IN/IN */
				mem_free(str(s));
				return 8;
			}
		/* must be in cidr notation (really) */
		r = atoi(p);
		if (r == -1) {
			mem_free(str(s));
			return 0;
		}
		cidr[4] = cidr[5] = cidr[6] = cidr[7] = 0xFF;
		if (r < 8) {
			cidr[4] = (0xFF << (8 - r));
			cidr[5] = cidr[6] = cidr[7] = 0x00;
		} else if (r < 16) {
			cidr[5] = (0xFF << (16 - r));
			cidr[6] = cidr[7] = 0x00;
		} else if (r < 24) {
			cidr[6] = (0xFF << (24 - r));
			cidr[7] = 0x00;
		} else {
			cidr[7] = (0xFF << (32 - r));
		}
		mem_free(str(s));
		return 8;
	} else {
		mem_free(str(s));
		return 0;
	}
}
static int inline socket_bind4(int fd, unsigned char ip[4], int port)
{
	struct sockaddr_in sin;

	memzero(&sin, sizeof(sin));

	sin.sin_family = PF_INET;
	/* Clib */
	sin.sin_port = htons(port);
	memcpy(&sin.sin_addr, ip, 4);

	return bind(fd, (struct sockaddr *)&sin, sizeof(sin));
}
static int inline socket_bind4_reuse(int fd, unsigned char ip[4], int port)
{
	int opt = 1;
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	return socket_bind4(fd, ip, port);
}
static int inline socket_peer4(int fd, unsigned char ip[4], int *port)
{
	struct sockaddr_in sin;
	int silen;

	memzero(&sin, sizeof(sin));

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

	if (sin.sin_family != PF_INET)
		return 0;

	memcpy(ip, &sin.sin_addr, 4);
	*port = ntohs(sin.sin_port);
	return 1;
}
static int inline socket_local4(int fd, unsigned char ip[4], int *port)
{
	struct sockaddr_in sin;
	int silen;

	memzero(&sin, sizeof(sin));

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

	if (sin.sin_family != PF_INET)
		return 0;

	memcpy(ip, &sin.sin_addr, 4);
	*port = ntohs(sin.sin_port);
	return 1;
}

static int inline socket_tcp4(void)
{
	int fd;

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

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

	memzero(&sa, sizeof(sa));

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

	memcpy(ip, &sa.sin_addr, 4);
	*port = ntohs(sa.sin_port);

	return r;
}
static int inline socket_recv4(int s, char *buf, int len, unsigned char ip[4], int *port)
{
	struct sockaddr_in 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;

	memcpy(ip, &sa.sin_addr, 4);
	*port = ntohs(sa.sin_port);

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

	memzero(&sa, sizeof(sa));

	sa.sin_family = PF_INET;
	sa.sin_port = htons(port);
	memcpy(&sa.sin_addr, ip, 4);

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

#endif


syntax highlighted by Code2HTML, v. 0.9.1