/* 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