network.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 965 行 · 第 1/2 页
C
965 行
/* * PostgreSQL type definitions for the INET and CIDR types. * * $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.47.2.1 2003/12/01 18:50:29 tgl Exp $ * * Jon Postel RIP 16 Oct 1998 */#include "postgres.h"#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "utils/builtins.h"#include "utils/inet.h"static Datum text_network(text *src, int type);static int32 network_cmp_internal(inet *a1, inet *a2);static int bitncmp(void *l, void *r, int n);static bool addressOK(unsigned char *a, int bits, int family);static int ip_addrsize(inet *inetptr);/* * Access macros. */#define ip_family(inetptr) \ (((inet_struct *)VARDATA(inetptr))->family)#define ip_bits(inetptr) \ (((inet_struct *)VARDATA(inetptr))->bits)#define ip_type(inetptr) \ (((inet_struct *)VARDATA(inetptr))->type)#define ip_addr(inetptr) \ (((inet_struct *)VARDATA(inetptr))->ip_addr)#define ip_maxbits(inetptr) \ (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128)/* * Return the number of bytes of storage needed for this data type. */static intip_addrsize(inet *inetptr){ switch (ip_family(inetptr)) { case PGSQL_AF_INET: return 4; case PGSQL_AF_INET6: return 16; default: return -1; }}/* Common input routine */static inet *network_in(char *src, int type){ int bits; inet *dst; dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); /* * First, check to see if this is an IPv6 or IPv4 address. IPv6 * addresses will have a : somewhere in them (several, in fact) so if * there is one present, assume it's V6, otherwise assume it's V4. */ if (strchr(src, ':') != NULL) ip_family(dst) = PGSQL_AF_INET6; else ip_family(dst) = PGSQL_AF_INET; bits = inet_net_pton(ip_family(dst), src, ip_addr(dst), type ? ip_addrsize(dst) : -1); if ((bits < 0) || (bits > ip_maxbits(dst))) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), /* translator: first %s is inet or cidr */ errmsg("invalid input syntax for type %s: \"%s\"", type ? "cidr" : "inet", src))); /* * Error check: CIDR values must not have any bits set beyond the * masklen. */ if (type) { if (!addressOK(ip_addr(dst), bits, ip_family(dst))) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid cidr value: \"%s\"", src), errdetail("Value has bits set to right of mask."))); } VARATT_SIZEP(dst) = VARHDRSZ + ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); ip_bits(dst) = bits; ip_type(dst) = type; return dst;}/* INET address reader. */Datuminet_in(PG_FUNCTION_ARGS){ char *src = PG_GETARG_CSTRING(0); PG_RETURN_INET_P(network_in(src, 0));}/* CIDR address reader. */Datumcidr_in(PG_FUNCTION_ARGS){ char *src = PG_GETARG_CSTRING(0); PG_RETURN_INET_P(network_in(src, 1));}/* * INET address output function. */Datuminet_out(PG_FUNCTION_ARGS){ inet *src = PG_GETARG_INET_P(0); char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; char *dst; int len; dst = inet_net_ntop(ip_family(src), ip_addr(src), ip_bits(src), tmp, sizeof(tmp)); if (dst == NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("could not format inet value: %m"))); /* For CIDR, add /n if not present */ if (ip_type(src) && strchr(tmp, '/') == NULL) { len = strlen(tmp); snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src)); } PG_RETURN_CSTRING(pstrdup(tmp));}/* share code with INET case */Datumcidr_out(PG_FUNCTION_ARGS){ return inet_out(fcinfo);}/* * inet_recv - converts external binary format to inet * * The external representation is (one byte apiece for) * family, bits, type, address length, address in network byte order. */Datuminet_recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); inet *addr; char *addrptr; int bits; int nb, i; /* make sure any unused bits in a CIDR value are zeroed */ addr = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ip_family(addr) = pq_getmsgbyte(buf); if (ip_family(addr) != PGSQL_AF_INET && ip_family(addr) != PGSQL_AF_INET6) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid address family in external \"inet\" value"))); bits = pq_getmsgbyte(buf); if (bits < 0 || bits > ip_maxbits(addr)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid bits in external \"inet\" value"))); ip_bits(addr) = bits; ip_type(addr) = pq_getmsgbyte(buf); if (ip_type(addr) != 0 && ip_type(addr) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid type in external \"inet\" value"))); nb = pq_getmsgbyte(buf); if (nb != ip_addrsize(addr)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid length in external \"inet\" value"))); VARATT_SIZEP(addr) = VARHDRSZ + ((char *) ip_addr(addr) - (char *) VARDATA(addr)) + ip_addrsize(addr); addrptr = (char *) ip_addr(addr); for (i = 0; i < nb; i++) addrptr[i] = pq_getmsgbyte(buf); /* * Error check: CIDR values must not have any bits set beyond the * masklen. */ if (ip_type(addr)) { if (!addressOK(ip_addr(addr), bits, ip_family(addr))) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid external \"cidr\" value"), errdetail("Value has bits set to right of mask."))); } PG_RETURN_INET_P(addr);}/* share code with INET case */Datumcidr_recv(PG_FUNCTION_ARGS){ return inet_recv(fcinfo);}/* * inet_send - converts inet to binary format */Datuminet_send(PG_FUNCTION_ARGS){ inet *addr = PG_GETARG_INET_P(0); StringInfoData buf; char *addrptr; int nb, i; pq_begintypsend(&buf); pq_sendbyte(&buf, ip_family(addr)); pq_sendbyte(&buf, ip_bits(addr)); pq_sendbyte(&buf, ip_type(addr)); nb = ip_addrsize(addr); if (nb < 0) nb = 0; pq_sendbyte(&buf, nb); addrptr = (char *) ip_addr(addr); for (i = 0; i < nb; i++) pq_sendbyte(&buf, addrptr[i]); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* share code with INET case */Datumcidr_send(PG_FUNCTION_ARGS){ return inet_send(fcinfo);}static Datumtext_network(text *src, int type){ int len = VARSIZE(src) - VARHDRSZ; char *str = palloc(len + 1); memcpy(str, VARDATA(src), len); *(str + len) = '\0'; PG_RETURN_INET_P(network_in(str, type));}Datumtext_cidr(PG_FUNCTION_ARGS){ return text_network(PG_GETARG_TEXT_P(0), 1);}Datumtext_inet(PG_FUNCTION_ARGS){ return text_network(PG_GETARG_TEXT_P(0), 0);}Datuminet_set_masklen(PG_FUNCTION_ARGS){ inet *src = PG_GETARG_INET_P(0); int bits = PG_GETARG_INT32(1); inet *dst; if (bits == -1) bits = ip_maxbits(src); if ((bits < 0) || (bits > ip_maxbits(src))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid mask length: %d", bits))); /* clone the original data */ dst = (inet *) palloc(VARSIZE(src)); memcpy(dst, src, VARSIZE(src)); ip_bits(dst) = bits; PG_RETURN_INET_P(dst);}/* * Basic comparison function for sorting and inet/cidr comparisons. * * Comparison is first on the common bits of the network part, then on * the length of the network part, and then on the whole unmasked address. * The effect is that the network part is the major sort key, and for * equal network parts we sort on the host part. Note this is only sane * for CIDR if address bits to the right of the mask are guaranteed zero; * otherwise logically-equal CIDRs might compare different. */static int32network_cmp_internal(inet *a1, inet *a2){ if (ip_family(a1) == ip_family(a2)) { int order; order = bitncmp(ip_addr(a1), ip_addr(a2), Min(ip_bits(a1), ip_bits(a2))); if (order != 0) return order; order = ((int) ip_bits(a1)) - ((int) ip_bits(a2)); if (order != 0) return order; return bitncmp(ip_addr(a1), ip_addr(a2), ip_maxbits(a1)); } return ip_family(a1) - ip_family(a2);}Datumnetwork_cmp(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); PG_RETURN_INT32(network_cmp_internal(a1, a2));}/* * Boolean ordering tests. */Datumnetwork_lt(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); PG_RETURN_BOOL(network_cmp_internal(a1, a2) < 0);}Datumnetwork_le(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); PG_RETURN_BOOL(network_cmp_internal(a1, a2) <= 0);}Datumnetwork_eq(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); PG_RETURN_BOOL(network_cmp_internal(a1, a2) == 0);}Datumnetwork_ge(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); PG_RETURN_BOOL(network_cmp_internal(a1, a2) >= 0);}Datumnetwork_gt(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); PG_RETURN_BOOL(network_cmp_internal(a1, a2) > 0);}Datumnetwork_ne(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); PG_RETURN_BOOL(network_cmp_internal(a1, a2) != 0);}/* * Boolean network-inclusion tests. */Datumnetwork_sub(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2) && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0); } PG_RETURN_BOOL(false);}Datumnetwork_subeq(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2) && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0); } PG_RETURN_BOOL(false);}Datumnetwork_sup(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2) && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0); } PG_RETURN_BOOL(false);}Datumnetwork_supeq(PG_FUNCTION_ARGS){ inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2) && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0); } PG_RETURN_BOOL(false);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?