summaryrefslogblamecommitdiffstats
path: root/host.c
blob: 89a8524f4be13ba1b9b47d1f83a4aa284540e6b1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                            
                                                   






                                     
                                                                                                    

                                                             


                                                  


                                                        




                                                                                                   
                                             

                                                                                                     























































                                                                                       











                                                                                                   
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netdb.h>
struct in_net {
	struct in_addr addr;
	struct in_addr mask;
};
#define POPCNT(y) int popcnt##y (uint##y##_t x) { \
	int c = 0; \
	for (int i = 0; i < y; i++) \
		if (1 << i & x) \
			c++; \
	return c; \
}
POPCNT(32)
struct in_net host (struct in_net n, unsigned long long int h /* number of host in the network */) {
	n.addr.s_addr = ntohl(n.addr.s_addr & n.mask.s_addr);
	n.mask.s_addr = ntohl(n.mask.s_addr);
	unsigned long long int c = 1;
	unsigned long int s = 0;
	for (unsigned long int i = 0; i < 32; i++)
		if (1 << i & ~n.mask.s_addr) {
			if (1 << s++ & h)
				n.addr.s_addr |= 1 << i;
			c *= 2;			/* if we instead indicated error via addr and */
		}				/* returned just addr, it would be impossible to */
	n.mask.s_addr = INADDR_BROADCAST;	/* scan 0.0.0.0/0 without immediately detecting */
	if (h >= c)				/* this false "error" and address 0.0.0.0 would */
		n.mask.s_addr = 0;		/* in fact actually be correct. */
	n.addr.s_addr = htonl(n.addr.s_addr);
	return n;				/* \/= this means host h is outside network */
} /* returns struct in_net: if .mask is not 255.255.255.255 (INADDR_BROADCAST), .addr is incorrect */
int resolve (const char * d, uint32_t * r) {
	struct addrinfo hints = {
		.ai_family = AF_INET,
		.ai_socktype = SOCK_DGRAM,
		.ai_flags = 0,
		.ai_protocol = 0,
		.ai_canonname = NULL,
		.ai_addr = NULL,
		.ai_next = NULL
	};
	struct addrinfo * result;
	int ret = getaddrinfo(d, NULL, &hints, &result);
	*r = ((struct sockaddr_in *) result->ai_addr)->sin_addr.s_addr; /* ah yes, C */
	freeaddrinfo(result);
	return ret;
}
struct in_net str2net (char * s) { /* blocking, resolving */
	struct in_net r = {
		.mask = {
			.s_addr = 0
		},
		.addr = {
			.s_addr = 0
		}
	};
	char * m = strchr(s, '/');
	char o = '\0';
	int e;
	if (m) {
		o = *m;
		*m++ = '\0';
	} else
		m = "32";
	fprintf(stderr, "str2net: resolving %s ... ", s);
	if ((e = resolve(s, &r.addr.s_addr))) {
		fprintf(stderr, "failed: %s\n", gai_strerror(e));
		goto r;
	}
	fprintf(stderr, " %s mask %s ...", inet_ntoa(r.addr), m);
	char * p;
	int x = strtoll(m, &p, 10);
	r.mask.s_addr = 0;
	for (int j = 0; j < x && j < 32; j++)
		r.mask.s_addr = r.mask.s_addr >> 1 | 1 << 31;
	r.mask.s_addr = htonl(r.mask.s_addr);
	if (*p)
		if ((e = resolve(m, &r.mask.s_addr))) {
			fprintf(stderr, "no: %s\n", gai_strerror(e));
			goto r;
		}
	fprintf(stderr, " %s\n", inet_ntoa(r.mask));
r:
	if (o)
		*--m = o;
	return r;
}
unsigned long long int ri (unsigned long long int v, int s) { /* 000 100 010 110 001 101 011 111 */
	int i = s-1;
	if (!(v & 1 << (s-1)))
		return v | 1 << (s-1);
	while (1) {
		if (!(v & 1 << i))
			return v | 1 << i;
		if (!i) /* rollover */
			return 0;
		v &= ~(1 << i--);
	}
}