Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/wapython
Path: blob/main/core/posix-node/src/netdb.zig
1067 views
1
const c = @import("c.zig");
2
const node = @import("node.zig");
3
const netdb = @cImport({
4
@cDefine("struct__OSUnalignedU16", "uint16_t");
5
@cDefine("struct__OSUnalignedU32", "uint32_t");
6
@cDefine("struct__OSUnalignedU64", "uint64_t");
7
@cInclude("netdb.h");
8
@cInclude("arpa/inet.h");
9
});
10
const std = @import("std");
11
const string = @cImport(@cInclude("string.h"));
12
13
pub fn register(env: c.napi_env, exports: c.napi_value) !void {
14
try node.registerFunction(env, exports, "gethostbyname", gethostbyname);
15
try node.registerFunction(env, exports, "gethostbyaddr", gethostbyaddr);
16
try node.registerFunction(env, exports, "_getaddrinfo", getaddrinfo);
17
try node.registerFunction(env, exports, "gai_strerror", gai_strerror);
18
try node.registerFunction(env, exports, "hstrerror", hstrerror);
19
}
20
21
pub const constants = .{
22
.c_import = netdb,
23
.names = [_][:0]const u8{
24
"AF_UNSPEC", "AF_UNIX", "AF_LOCAL", "AF_INET", "AF_SNA", "AF_DECnet", "AF_APPLETALK", "AF_ROUTE", "AF_IPX", "AF_ISDN", "AF_INET6", "AF_MAX", // AF_= address format
25
"AI_PASSIVE", "AI_CANONNAME", "AI_NUMERICHOST", "AI_V4MAPPED", "AI_ALL", "AI_ADDRCONFIG", "AI_NUMERICSERV", // AI = address info
26
// Commenting out these EAI, since they are negative on Linux, which is really annoying.
27
// "EAI_BADFLAGS", "EAI_NONAME", "EAI_AGAIN", "EAI_FAIL", "EAI_FAMILY", "EAI_SOCKTYPE", "EAI_SERVICE", "EAI_MEMORY", "EAI_SYSTEM", "EAI_OVERFLOW", // errors for the getaddrinfo function
28
"SOCK_STREAM", "SOCK_DGRAM", "SOCK_RAW", "SOCK_RDM", "SOCK_SEQPACKET",
29
},
30
};
31
32
// struct hostent *gethostbyname(const char *name);
33
// struct hostent
34
// {
35
// char *h_name; /* Official domain name of host */
36
// char **h_aliases; /* Null-terminated array of domain names */
37
// int h_addrtype; /* Host address type (AF_INET) */
38
// int h_length; /* Length of an address, in bytes */
39
// char **h_addr_list; /* Null-terminated array of in_addr structs */
40
// };
41
42
fn gethostbyname(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
43
const argv = node.getArgv(env, info, 1) catch return null;
44
var buf: [1024]u8 = undefined;
45
node.stringFromValue(env, argv[0], "name", 1024, &buf) catch return null;
46
const hostent: *netdb.hostent = netdb.gethostbyname(&buf) orelse {
47
node.throwError(env, "gethostbyname system call returned a null pointer");
48
return null;
49
};
50
return createHostent(env, hostent);
51
}
52
53
// struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type);
54
//
55
// Usage: gethostbyaddr("64.233.187.99") or gethostbyaddr("2001:4860:4860::8888")
56
fn gethostbyaddr(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
57
var buf: [40]u8 = undefined;
58
const argv = node.getArgv(env, info, 1) catch return null;
59
node.stringFromValue(env, argv[0], "ip", 40, &buf) catch return null;
60
var i: usize = 0;
61
var v6: bool = false;
62
while (buf[i] != 0) : (i += 1) {
63
if (buf[i] == ':') {
64
v6 = true;
65
break;
66
}
67
}
68
if (v6) {
69
return gethostbyaddr_v6(env, @ptrCast([*:0]u8, &buf));
70
} else {
71
return gethostbyaddr_v4(env, @ptrCast([*:0]u8, &buf));
72
}
73
}
74
75
fn gethostbyaddr_v4(env: c.napi_env, bufPtr: [*:0]u8) callconv(.C) c.napi_value {
76
var addr = netdb.inet_addr(bufPtr);
77
const hostent: *netdb.hostent = netdb.gethostbyaddr(&addr, @sizeOf(@TypeOf(addr)), netdb.AF_INET) orelse {
78
node.throwError(env, "gethostbyaddr system call returned a null pointer");
79
return null;
80
};
81
return createHostent(env, hostent);
82
}
83
84
fn gethostbyaddr_v6(env: c.napi_env, bufPtr: [*:0]u8) callconv(.C) c.napi_value {
85
var addr: netdb.in6_addr = undefined;
86
switch (netdb.inet_pton(netdb.AF_INET6, bufPtr, &addr)) {
87
0 => {
88
node.throwError(env, "gethostbyaddr_v6 -- character string does not represent a valid network address in the specified address family");
89
return null;
90
},
91
-1 => {
92
node.throwError(env, "gethostbyaddr_v6 -- address family is invalid");
93
return null;
94
},
95
else => {},
96
}
97
const hostent: *netdb.hostent = netdb.gethostbyaddr(&addr, @sizeOf(@TypeOf(addr)), netdb.AF_INET6) orelse {
98
node.throwError(env, "gethostbyaddr system call returned null pointer");
99
return null;
100
};
101
return createHostent(env, hostent);
102
}
103
104
fn createHostent(env: c.napi_env, hostent: *netdb.hostent) c.napi_value {
105
var object = node.createObject(env, "") catch return null;
106
107
// h_name
108
const h_name = node.createStringFromPtr(env, hostent.h_name, "hostent.h_name") catch return null;
109
node.setNamedProperty(env, object, "h_name", h_name, "") catch return null;
110
111
// h_addrtype
112
if (hostent.h_addrtype != netdb.AF_INET and hostent.h_addrtype != netdb.AF_INET6) {
113
node.throwError(env, "internal bug -- invalid h_addrtype");
114
return null;
115
}
116
const h_addrtype = node.create_i32(env, hostent.h_addrtype, "h_addrtype") catch return null;
117
node.setNamedProperty(env, object, "h_addrtype", h_addrtype, "") catch return null;
118
119
// h_length
120
const h_length = node.create_i32(env, hostent.h_length, "h_length") catch return null;
121
node.setNamedProperty(env, object, "h_length", h_length, "") catch return null;
122
123
// h_addr_list
124
// how many addresses:
125
var i: u32 = 0;
126
while (hostent.h_addr_list[i] != null) : (i += 1) {}
127
// convert them to node strings:
128
var h_addr_list = node.createArray(env, i, "h_addr_list") catch return null;
129
node.setNamedProperty(env, object, "h_addr_list", h_addr_list, "") catch return null;
130
if (i > 0) {
131
i -= 1;
132
while (true) : (i -= 1) {
133
var ip: c.napi_value = undefined;
134
var dst: [40]u8 = undefined;
135
if (netdb.inet_ntop(hostent.h_addrtype, hostent.h_addr_list[i], &dst, dst.len) == null) {
136
node.throwError(env, "error converting address to string");
137
return null;
138
}
139
ip = node.createStringFromPtr(env, @ptrCast([*:0]u8, &dst), "converting ip adddress to string") catch return null;
140
node.setElement(env, h_addr_list, i, ip, "error setting ip address in h_addr_list") catch return null;
141
if (i == 0) break; // have to do this, since if i = 0 then i-=1 is 2^32-1, since i is unsigned!
142
}
143
}
144
145
// h_aliases
146
// how many aliases?
147
i = 0;
148
while (hostent.h_aliases[i] != null) : (i += 1) {}
149
// convert them to node strings:
150
var h_aliases = node.createArray(env, i, "h_aliases") catch return null;
151
node.setNamedProperty(env, object, "h_aliases", h_aliases, "") catch return null;
152
if (i > 0) {
153
i -= 1;
154
while (true) : (i -= 1) {
155
const alias = node.createStringFromPtr(env, hostent.h_aliases[i], "h_aliases[i]") catch return null;
156
node.setElement(env, h_aliases, i, alias, "error setting alias in h_aliases") catch return null;
157
if (i == 0) break;
158
}
159
}
160
return object;
161
}
162
163
//////////////////////////
164
// int getaddrinfo(const char *restrict node,
165
// const char *restrict service,
166
// const struct addrinfo *restrict hints,
167
// struct addrinfo **restrict res);
168
// void freeaddrinfo(struct addrinfo *res);
169
//
170
//
171
// call like this:
172
//
173
// getaddrinfo0(node:string, service:string, hint_flags:number, hint_family:number, hint_socktype:number, hint_protocol:number)
174
//
175
// all arguments must be given, though the hints can all be 0. In index.ts
176
// we provide a nicer interface.
177
178
fn getaddrinfo(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
179
const argv = node.getArgv(env, info, 6) catch return null;
180
var nodeName: [256]u8 = undefined; // domain names are limited to 253 chars
181
node.stringFromValue(env, argv[0], "node", 256, &nodeName) catch return null;
182
var service: [256]u8 = undefined; // these are really short, e.g., "ftp"
183
node.stringFromValue(env, argv[1], "service", 256, &service) catch return null;
184
const hint_flags = node.i32FromValue(env, argv[2], "hint_flags") catch return null;
185
const hint_family = node.i32FromValue(env, argv[3], "hint_family") catch return null;
186
const hint_socktype = node.i32FromValue(env, argv[4], "hint_socktype") catch return null;
187
const hint_protocol = node.i32FromValue(env, argv[5], "hint_protocol") catch return null;
188
189
const hints = netdb.addrinfo{ .ai_flags = hint_flags, .ai_family = hint_family, .ai_socktype = hint_socktype, .ai_protocol = hint_protocol, .ai_addrlen = 0, .ai_addr = 0, .ai_canonname = 0, .ai_next = 0 };
190
var res: *netdb.addrinfo = undefined;
191
const errcode = netdb.getaddrinfo(&nodeName, &service, &hints, @ptrCast([*c][*c]netdb.addrinfo, &res));
192
if (errcode != 0) {
193
node.throwErrorNumber(env, @ptrCast([*:0]const u8, netdb.gai_strerror(errcode)), errcode);
194
return null;
195
}
196
const addrinfo = createAddrinfoArray(env, res);
197
netdb.freeaddrinfo(res);
198
return addrinfo;
199
}
200
201
// struct sockaddr {
202
// __uint8_t sa_len; /* total length */
203
// sa_family_t sa_family; /* [XSI] address family */
204
// char sa_data[14]; /* [XSI] addr value (actually larger) */
205
// };
206
//
207
const sockaddr = struct { sa_len: u8, sa_family: u8, sa_data: [14]u8 };
208
209
fn createAddrinfoArray(env: c.napi_env, addrinfo: ?*netdb.addrinfo) c.napi_value {
210
// determine the length of the linked list.
211
var len: u32 = 0;
212
var cur = addrinfo;
213
while (cur != null) : (cur = (cur orelse unreachable).ai_next) {
214
len += 1;
215
}
216
var array = node.createArray(env, len, "creating array to hold addrinfo objects") catch return null;
217
cur = addrinfo;
218
var index: u32 = 0;
219
while (cur != null) : (cur = (cur orelse unreachable).ai_next) {
220
const info = cur orelse unreachable;
221
node.setElement(env, array, index, createAddrinfo(env, info), "copying data into array of addrinfo objects") catch return null;
222
index += 1;
223
}
224
return array;
225
}
226
227
fn createAddrinfo(env: c.napi_env, addrinfo: *netdb.addrinfo) c.napi_value {
228
var object = node.createObject(env, "") catch return null;
229
const ai_flags = node.create_i32(env, addrinfo.ai_flags, "ai_flags") catch return null;
230
node.setNamedProperty(env, object, "ai_flags", ai_flags, "") catch return null;
231
232
const ai_family = node.create_i32(env, addrinfo.ai_family, "ai_family") catch return null;
233
node.setNamedProperty(env, object, "ai_family", ai_family, "") catch return null;
234
235
const ai_socktype = node.create_i32(env, addrinfo.ai_socktype, "ai_socktype") catch return null;
236
node.setNamedProperty(env, object, "ai_socktype", ai_socktype, "") catch return null;
237
238
const ai_protocol = node.create_i32(env, addrinfo.ai_protocol, "ai_protocol") catch return null;
239
node.setNamedProperty(env, object, "ai_protocol", ai_protocol, "") catch return null;
240
241
const ai_addrlen = node.create_u32(env, addrinfo.ai_addrlen, "ai_addrlen") catch return null;
242
node.setNamedProperty(env, object, "ai_addrlen", ai_addrlen, "") catch return null;
243
244
if (addrinfo.ai_canonname != null) {
245
const ai_canonname = node.createStringFromPtr(env, addrinfo.ai_canonname, "ai_canonname") catch return null;
246
node.setNamedProperty(env, object, "ai_canonname", ai_canonname, "") catch return null;
247
}
248
249
const ai_addr = @ptrCast(*sockaddr, addrinfo.ai_addr);
250
const sa_len = node.create_u32(env, ai_addr.sa_len, "sockaddr.sa_len") catch return null;
251
node.setNamedProperty(env, object, "sa_len", sa_len, "") catch return null;
252
const sa_family = node.create_u32(env, ai_addr.sa_family, "sockaddr.sa_family") catch return null;
253
node.setNamedProperty(env, object, "sa_family", sa_family, "") catch return null;
254
255
// "The sa_len field contains the length of the sa_data field. " -- from some official docs on an IBM website that are
256
// *DEFINITELY WRONG*. I tried with both sa_len and sa_len - 2, and the latter
257
// is definitely right. There's just random extra noise otherwise.
258
// Also, on Linux sa_len is not the length at all. So I'm using addrinfo.ai_addrlen-2, which seems right everywhere.
259
const sa_data = node.createBufferCopy(env, &ai_addr.sa_data, addrinfo.ai_addrlen - 2, "sa_data") catch return null;
260
node.setNamedProperty(env, object, "sa_data", sa_data, "") catch return null;
261
262
return object;
263
}
264
265
// const char *gai_strerror(int errcode);
266
fn gai_strerror(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
267
const argv = node.getArgv(env, info, 1) catch return null;
268
const errcode = node.i32FromValue(env, argv[0], "errcode") catch return null;
269
const err = netdb.gai_strerror(errcode) orelse {
270
node.throwError(env, "invalid error code");
271
return null;
272
};
273
return node.createStringFromPtr(env, err, "err") catch return null;
274
}
275
276
// const char *hstrerror(int err);
277
fn hstrerror(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
278
const argv = node.getArgv(env, info, 1) catch return null;
279
const errcode = node.i32FromValue(env, argv[0], "errcode") catch return null;
280
const err = netdb.hstrerror(errcode) orelse {
281
node.throwError(env, "invalid error code");
282
return null;
283
};
284
return node.createStringFromPtr(env, err, "err") catch return null;
285
}
286
287