-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpg_inet_addr.c
130 lines (104 loc) · 3.61 KB
/
pg_inet_addr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "postgres.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netdb.h>
#include "funcapi.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "utils/builtins.h"
//#include "utils/inet.h"
#include "utils/tuplestore.h"
PG_MODULE_MAGIC;
Datum pg_inet_addr(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pg_inet_addr);
Datum
pg_inet_addr(PG_FUNCTION_ARGS)
{
#define PG_INET_ADDR_COLS 4
struct ifaddrs *ifaddr, *ifa;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not " \
"allowed in this context")));
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);
if (getifaddrs(&ifaddr) == -1)
elog(ERROR, "getifaddrs failed: %s", strerror(errno));
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
/* for each row */
Datum values[PG_INET_ADDR_COLS];
bool nulls[PG_INET_ADDR_COLS];
int h, n;
int family;
char address[NI_MAXHOST];
char netmask[INET6_ADDRSTRLEN];
if (ifa->ifa_addr == NULL)
continue;
address[0] = '\0';
netmask[0] = '\0';
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
family = ifa->ifa_addr->sa_family;
if (family == AF_INET || family == AF_INET6)
{
/* host address */
h = getnameinfo(ifa->ifa_addr, (family == AF_INET) ?
sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (h != 0)
elog(ERROR, "address: getnameinfo failed: %s", gai_strerror(errno));
if (ifa->ifa_netmask == NULL)
elog(DEBUG1, "%s: netmask is null", address);
/* host netmask */
n = getnameinfo(ifa->ifa_netmask, (family == AF_INET) ?
sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
netmask, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
if (n != 0)
elog(ERROR, "netmask: getnameinfo failed: %s", gai_strerror(errno));
elog(DEBUG1, "interface: %s ; address: %s ; netmask: %s ; family; %s", ifa->ifa_name, address, netmask, (family == AF_INET) ? "IPv4" : "IPv6");
values[0] = CStringGetTextDatum(ifa->ifa_name);
if (h == 0)
// values[1] = DirectFunctionCall1(inet_in, CStringGetDatum(address));
values[1] = CStringGetTextDatum(address);
else
nulls[1] = true;
if (n == 0)
// values[2] = DirectFunctionCall1(inet_in, CStringGetDatum(netmask));
values[2] = CStringGetTextDatum(netmask);
else
nulls[2] = true;
if (family == AF_INET)
values[3] = CStringGetTextDatum("IPv4");
else if (family == AF_INET6)
values[3] = CStringGetTextDatum("IPv6");
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
}
freeifaddrs(ifaddr);
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
return (Datum) 0;
}