diff options
Diffstat (limited to 'vendor/luasocket/src/inet.c')
-rwxr-xr-x | vendor/luasocket/src/inet.c | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/vendor/luasocket/src/inet.c b/vendor/luasocket/src/inet.c new file mode 100755 index 00000000..138c9abe --- /dev/null +++ b/vendor/luasocket/src/inet.c | |||
@@ -0,0 +1,537 @@ | |||
1 | /*=========================================================================*\ | ||
2 | * Internet domain functions | ||
3 | * LuaSocket toolkit | ||
4 | \*=========================================================================*/ | ||
5 | #include "luasocket.h" | ||
6 | #include "inet.h" | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | |||
12 | /*=========================================================================*\ | ||
13 | * Internal function prototypes. | ||
14 | \*=========================================================================*/ | ||
15 | static int inet_global_toip(lua_State *L); | ||
16 | static int inet_global_getaddrinfo(lua_State *L); | ||
17 | static int inet_global_tohostname(lua_State *L); | ||
18 | static int inet_global_getnameinfo(lua_State *L); | ||
19 | static void inet_pushresolved(lua_State *L, struct hostent *hp); | ||
20 | static int inet_global_gethostname(lua_State *L); | ||
21 | |||
22 | /* DNS functions */ | ||
23 | static luaL_Reg func[] = { | ||
24 | { "toip", inet_global_toip}, | ||
25 | { "getaddrinfo", inet_global_getaddrinfo}, | ||
26 | { "tohostname", inet_global_tohostname}, | ||
27 | { "getnameinfo", inet_global_getnameinfo}, | ||
28 | { "gethostname", inet_global_gethostname}, | ||
29 | { NULL, NULL} | ||
30 | }; | ||
31 | |||
32 | /*-------------------------------------------------------------------------*\ | ||
33 | * Initializes module | ||
34 | \*-------------------------------------------------------------------------*/ | ||
35 | int inet_open(lua_State *L) | ||
36 | { | ||
37 | lua_pushstring(L, "dns"); | ||
38 | lua_newtable(L); | ||
39 | luaL_setfuncs(L, func, 0); | ||
40 | lua_settable(L, -3); | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | /*=========================================================================*\ | ||
45 | * Global Lua functions | ||
46 | \*=========================================================================*/ | ||
47 | /*-------------------------------------------------------------------------*\ | ||
48 | * Returns all information provided by the resolver given a host name | ||
49 | * or ip address | ||
50 | \*-------------------------------------------------------------------------*/ | ||
51 | static int inet_gethost(const char *address, struct hostent **hp) { | ||
52 | struct in_addr addr; | ||
53 | if (inet_aton(address, &addr)) | ||
54 | return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); | ||
55 | else | ||
56 | return socket_gethostbyname(address, hp); | ||
57 | } | ||
58 | |||
59 | /*-------------------------------------------------------------------------*\ | ||
60 | * Returns all information provided by the resolver given a host name | ||
61 | * or ip address | ||
62 | \*-------------------------------------------------------------------------*/ | ||
63 | static int inet_global_tohostname(lua_State *L) { | ||
64 | const char *address = luaL_checkstring(L, 1); | ||
65 | struct hostent *hp = NULL; | ||
66 | int err = inet_gethost(address, &hp); | ||
67 | if (err != IO_DONE) { | ||
68 | lua_pushnil(L); | ||
69 | lua_pushstring(L, socket_hoststrerror(err)); | ||
70 | return 2; | ||
71 | } | ||
72 | lua_pushstring(L, hp->h_name); | ||
73 | inet_pushresolved(L, hp); | ||
74 | return 2; | ||
75 | } | ||
76 | |||
77 | static int inet_global_getnameinfo(lua_State *L) { | ||
78 | char hbuf[NI_MAXHOST]; | ||
79 | char sbuf[NI_MAXSERV]; | ||
80 | int i, ret; | ||
81 | struct addrinfo hints; | ||
82 | struct addrinfo *resolved, *iter; | ||
83 | const char *host = luaL_optstring(L, 1, NULL); | ||
84 | const char *serv = luaL_optstring(L, 2, NULL); | ||
85 | |||
86 | if (!(host || serv)) | ||
87 | luaL_error(L, "host and serv cannot be both nil"); | ||
88 | |||
89 | memset(&hints, 0, sizeof(hints)); | ||
90 | hints.ai_socktype = SOCK_STREAM; | ||
91 | hints.ai_family = AF_UNSPEC; | ||
92 | |||
93 | ret = getaddrinfo(host, serv, &hints, &resolved); | ||
94 | if (ret != 0) { | ||
95 | lua_pushnil(L); | ||
96 | lua_pushstring(L, socket_gaistrerror(ret)); | ||
97 | return 2; | ||
98 | } | ||
99 | |||
100 | lua_newtable(L); | ||
101 | for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { | ||
102 | getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, | ||
103 | hbuf, host? (socklen_t) sizeof(hbuf): 0, | ||
104 | sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); | ||
105 | if (host) { | ||
106 | lua_pushnumber(L, i); | ||
107 | lua_pushstring(L, hbuf); | ||
108 | lua_settable(L, -3); | ||
109 | } | ||
110 | } | ||
111 | freeaddrinfo(resolved); | ||
112 | |||
113 | if (serv) { | ||
114 | lua_pushstring(L, sbuf); | ||
115 | return 2; | ||
116 | } else { | ||
117 | return 1; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /*-------------------------------------------------------------------------*\ | ||
122 | * Returns all information provided by the resolver given a host name | ||
123 | * or ip address | ||
124 | \*-------------------------------------------------------------------------*/ | ||
125 | static int inet_global_toip(lua_State *L) | ||
126 | { | ||
127 | const char *address = luaL_checkstring(L, 1); | ||
128 | struct hostent *hp = NULL; | ||
129 | int err = inet_gethost(address, &hp); | ||
130 | if (err != IO_DONE) { | ||
131 | lua_pushnil(L); | ||
132 | lua_pushstring(L, socket_hoststrerror(err)); | ||
133 | return 2; | ||
134 | } | ||
135 | lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); | ||
136 | inet_pushresolved(L, hp); | ||
137 | return 2; | ||
138 | } | ||
139 | |||
140 | int inet_optfamily(lua_State* L, int narg, const char* def) | ||
141 | { | ||
142 | static const char* optname[] = { "unspec", "inet", "inet6", NULL }; | ||
143 | static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 }; | ||
144 | |||
145 | return optvalue[luaL_checkoption(L, narg, def, optname)]; | ||
146 | } | ||
147 | |||
148 | int inet_optsocktype(lua_State* L, int narg, const char* def) | ||
149 | { | ||
150 | static const char* optname[] = { "stream", "dgram", NULL }; | ||
151 | static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 }; | ||
152 | |||
153 | return optvalue[luaL_checkoption(L, narg, def, optname)]; | ||
154 | } | ||
155 | |||
156 | static int inet_global_getaddrinfo(lua_State *L) | ||
157 | { | ||
158 | const char *hostname = luaL_checkstring(L, 1); | ||
159 | struct addrinfo *iterator = NULL, *resolved = NULL; | ||
160 | struct addrinfo hints; | ||
161 | int i = 1, ret = 0; | ||
162 | memset(&hints, 0, sizeof(hints)); | ||
163 | hints.ai_socktype = SOCK_STREAM; | ||
164 | hints.ai_family = AF_UNSPEC; | ||
165 | ret = getaddrinfo(hostname, NULL, &hints, &resolved); | ||
166 | if (ret != 0) { | ||
167 | lua_pushnil(L); | ||
168 | lua_pushstring(L, socket_gaistrerror(ret)); | ||
169 | return 2; | ||
170 | } | ||
171 | lua_newtable(L); | ||
172 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | ||
173 | char hbuf[NI_MAXHOST]; | ||
174 | ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, | ||
175 | hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); | ||
176 | if (ret){ | ||
177 | freeaddrinfo(resolved); | ||
178 | lua_pushnil(L); | ||
179 | lua_pushstring(L, socket_gaistrerror(ret)); | ||
180 | return 2; | ||
181 | } | ||
182 | lua_pushnumber(L, i); | ||
183 | lua_newtable(L); | ||
184 | switch (iterator->ai_family) { | ||
185 | case AF_INET: | ||
186 | lua_pushliteral(L, "family"); | ||
187 | lua_pushliteral(L, "inet"); | ||
188 | lua_settable(L, -3); | ||
189 | break; | ||
190 | case AF_INET6: | ||
191 | lua_pushliteral(L, "family"); | ||
192 | lua_pushliteral(L, "inet6"); | ||
193 | lua_settable(L, -3); | ||
194 | break; | ||
195 | case AF_UNSPEC: | ||
196 | lua_pushliteral(L, "family"); | ||
197 | lua_pushliteral(L, "unspec"); | ||
198 | lua_settable(L, -3); | ||
199 | break; | ||
200 | default: | ||
201 | lua_pushliteral(L, "family"); | ||
202 | lua_pushliteral(L, "unknown"); | ||
203 | lua_settable(L, -3); | ||
204 | break; | ||
205 | } | ||
206 | lua_pushliteral(L, "addr"); | ||
207 | lua_pushstring(L, hbuf); | ||
208 | lua_settable(L, -3); | ||
209 | lua_settable(L, -3); | ||
210 | i++; | ||
211 | } | ||
212 | freeaddrinfo(resolved); | ||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | /*-------------------------------------------------------------------------*\ | ||
217 | * Gets the host name | ||
218 | \*-------------------------------------------------------------------------*/ | ||
219 | static int inet_global_gethostname(lua_State *L) | ||
220 | { | ||
221 | char name[257]; | ||
222 | name[256] = '\0'; | ||
223 | if (gethostname(name, 256) < 0) { | ||
224 | lua_pushnil(L); | ||
225 | lua_pushstring(L, socket_strerror(errno)); | ||
226 | return 2; | ||
227 | } else { | ||
228 | lua_pushstring(L, name); | ||
229 | return 1; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | /*=========================================================================*\ | ||
234 | * Lua methods | ||
235 | \*=========================================================================*/ | ||
236 | /*-------------------------------------------------------------------------*\ | ||
237 | * Retrieves socket peer name | ||
238 | \*-------------------------------------------------------------------------*/ | ||
239 | int inet_meth_getpeername(lua_State *L, p_socket ps, int family) | ||
240 | { | ||
241 | int err; | ||
242 | struct sockaddr_storage peer; | ||
243 | socklen_t peer_len = sizeof(peer); | ||
244 | char name[INET6_ADDRSTRLEN]; | ||
245 | char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ | ||
246 | if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { | ||
247 | lua_pushnil(L); | ||
248 | lua_pushstring(L, socket_strerror(errno)); | ||
249 | return 2; | ||
250 | } | ||
251 | err = getnameinfo((struct sockaddr *) &peer, peer_len, | ||
252 | name, INET6_ADDRSTRLEN, | ||
253 | port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); | ||
254 | if (err) { | ||
255 | lua_pushnil(L); | ||
256 | lua_pushstring(L, LUA_GAI_STRERROR(err)); | ||
257 | return 2; | ||
258 | } | ||
259 | lua_pushstring(L, name); | ||
260 | lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); | ||
261 | switch (family) { | ||
262 | case AF_INET: lua_pushliteral(L, "inet"); break; | ||
263 | case AF_INET6: lua_pushliteral(L, "inet6"); break; | ||
264 | case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; | ||
265 | default: lua_pushliteral(L, "unknown"); break; | ||
266 | } | ||
267 | return 3; | ||
268 | } | ||
269 | |||
270 | /*-------------------------------------------------------------------------*\ | ||
271 | * Retrieves socket local name | ||
272 | \*-------------------------------------------------------------------------*/ | ||
273 | int inet_meth_getsockname(lua_State *L, p_socket ps, int family) | ||
274 | { | ||
275 | int err; | ||
276 | struct sockaddr_storage peer; | ||
277 | socklen_t peer_len = sizeof(peer); | ||
278 | char name[INET6_ADDRSTRLEN]; | ||
279 | char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ | ||
280 | if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) { | ||
281 | lua_pushnil(L); | ||
282 | lua_pushstring(L, socket_strerror(errno)); | ||
283 | return 2; | ||
284 | } | ||
285 | err=getnameinfo((struct sockaddr *)&peer, peer_len, | ||
286 | name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); | ||
287 | if (err) { | ||
288 | lua_pushnil(L); | ||
289 | lua_pushstring(L, LUA_GAI_STRERROR(err)); | ||
290 | return 2; | ||
291 | } | ||
292 | lua_pushstring(L, name); | ||
293 | lua_pushstring(L, port); | ||
294 | switch (family) { | ||
295 | case AF_INET: lua_pushliteral(L, "inet"); break; | ||
296 | case AF_INET6: lua_pushliteral(L, "inet6"); break; | ||
297 | case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; | ||
298 | default: lua_pushliteral(L, "unknown"); break; | ||
299 | } | ||
300 | return 3; | ||
301 | } | ||
302 | |||
303 | /*=========================================================================*\ | ||
304 | * Internal functions | ||
305 | \*=========================================================================*/ | ||
306 | /*-------------------------------------------------------------------------*\ | ||
307 | * Passes all resolver information to Lua as a table | ||
308 | \*-------------------------------------------------------------------------*/ | ||
309 | static void inet_pushresolved(lua_State *L, struct hostent *hp) | ||
310 | { | ||
311 | char **alias; | ||
312 | struct in_addr **addr; | ||
313 | int i, resolved; | ||
314 | lua_newtable(L); resolved = lua_gettop(L); | ||
315 | lua_pushstring(L, "name"); | ||
316 | lua_pushstring(L, hp->h_name); | ||
317 | lua_settable(L, resolved); | ||
318 | lua_pushstring(L, "ip"); | ||
319 | lua_pushstring(L, "alias"); | ||
320 | i = 1; | ||
321 | alias = hp->h_aliases; | ||
322 | lua_newtable(L); | ||
323 | if (alias) { | ||
324 | while (*alias) { | ||
325 | lua_pushnumber(L, i); | ||
326 | lua_pushstring(L, *alias); | ||
327 | lua_settable(L, -3); | ||
328 | i++; alias++; | ||
329 | } | ||
330 | } | ||
331 | lua_settable(L, resolved); | ||
332 | i = 1; | ||
333 | lua_newtable(L); | ||
334 | addr = (struct in_addr **) hp->h_addr_list; | ||
335 | if (addr) { | ||
336 | while (*addr) { | ||
337 | lua_pushnumber(L, i); | ||
338 | lua_pushstring(L, inet_ntoa(**addr)); | ||
339 | lua_settable(L, -3); | ||
340 | i++; addr++; | ||
341 | } | ||
342 | } | ||
343 | lua_settable(L, resolved); | ||
344 | } | ||
345 | |||
346 | /*-------------------------------------------------------------------------*\ | ||
347 | * Tries to create a new inet socket | ||
348 | \*-------------------------------------------------------------------------*/ | ||
349 | const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { | ||
350 | const char *err = socket_strerror(socket_create(ps, family, type, protocol)); | ||
351 | if (err == NULL && family == AF_INET6) { | ||
352 | int yes = 1; | ||
353 | setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); | ||
354 | } | ||
355 | return err; | ||
356 | } | ||
357 | |||
358 | /*-------------------------------------------------------------------------*\ | ||
359 | * "Disconnects" a DGRAM socket | ||
360 | \*-------------------------------------------------------------------------*/ | ||
361 | const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) | ||
362 | { | ||
363 | switch (family) { | ||
364 | case AF_INET: { | ||
365 | struct sockaddr_in sin; | ||
366 | memset((char *) &sin, 0, sizeof(sin)); | ||
367 | sin.sin_family = AF_UNSPEC; | ||
368 | sin.sin_addr.s_addr = INADDR_ANY; | ||
369 | return socket_strerror(socket_connect(ps, (SA *) &sin, | ||
370 | sizeof(sin), tm)); | ||
371 | } | ||
372 | case AF_INET6: { | ||
373 | struct sockaddr_in6 sin6; | ||
374 | struct in6_addr addrany = IN6ADDR_ANY_INIT; | ||
375 | memset((char *) &sin6, 0, sizeof(sin6)); | ||
376 | sin6.sin6_family = AF_UNSPEC; | ||
377 | sin6.sin6_addr = addrany; | ||
378 | return socket_strerror(socket_connect(ps, (SA *) &sin6, | ||
379 | sizeof(sin6), tm)); | ||
380 | } | ||
381 | } | ||
382 | return NULL; | ||
383 | } | ||
384 | |||
385 | /*-------------------------------------------------------------------------*\ | ||
386 | * Tries to connect to remote address (address, port) | ||
387 | \*-------------------------------------------------------------------------*/ | ||
388 | const char *inet_tryconnect(p_socket ps, int *family, const char *address, | ||
389 | const char *serv, p_timeout tm, struct addrinfo *connecthints) | ||
390 | { | ||
391 | struct addrinfo *iterator = NULL, *resolved = NULL; | ||
392 | const char *err = NULL; | ||
393 | int current_family = *family; | ||
394 | /* try resolving */ | ||
395 | err = socket_gaistrerror(getaddrinfo(address, serv, | ||
396 | connecthints, &resolved)); | ||
397 | if (err != NULL) { | ||
398 | if (resolved) freeaddrinfo(resolved); | ||
399 | return err; | ||
400 | } | ||
401 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | ||
402 | timeout_markstart(tm); | ||
403 | /* create new socket if necessary. if there was no | ||
404 | * bind, we need to create one for every new family | ||
405 | * that shows up while iterating. if there was a | ||
406 | * bind, all families will be the same and we will | ||
407 | * not enter this branch. */ | ||
408 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { | ||
409 | socket_destroy(ps); | ||
410 | err = inet_trycreate(ps, iterator->ai_family, | ||
411 | iterator->ai_socktype, iterator->ai_protocol); | ||
412 | if (err) continue; | ||
413 | current_family = iterator->ai_family; | ||
414 | /* set non-blocking before connect */ | ||
415 | socket_setnonblocking(ps); | ||
416 | } | ||
417 | /* try connecting to remote address */ | ||
418 | err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, | ||
419 | (socklen_t) iterator->ai_addrlen, tm)); | ||
420 | /* if success or timeout is zero, break out of loop */ | ||
421 | if (err == NULL || timeout_iszero(tm)) { | ||
422 | *family = current_family; | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | freeaddrinfo(resolved); | ||
427 | /* here, if err is set, we failed */ | ||
428 | return err; | ||
429 | } | ||
430 | |||
431 | /*-------------------------------------------------------------------------*\ | ||
432 | * Tries to accept a socket | ||
433 | \*-------------------------------------------------------------------------*/ | ||
434 | const char *inet_tryaccept(p_socket server, int family, p_socket client, | ||
435 | p_timeout tm) { | ||
436 | socklen_t len; | ||
437 | t_sockaddr_storage addr; | ||
438 | switch (family) { | ||
439 | case AF_INET6: len = sizeof(struct sockaddr_in6); break; | ||
440 | case AF_INET: len = sizeof(struct sockaddr_in); break; | ||
441 | default: len = sizeof(addr); break; | ||
442 | } | ||
443 | return socket_strerror(socket_accept(server, client, (SA *) &addr, | ||
444 | &len, tm)); | ||
445 | } | ||
446 | |||
447 | /*-------------------------------------------------------------------------*\ | ||
448 | * Tries to bind socket to (address, port) | ||
449 | \*-------------------------------------------------------------------------*/ | ||
450 | const char *inet_trybind(p_socket ps, int *family, const char *address, | ||
451 | const char *serv, struct addrinfo *bindhints) { | ||
452 | struct addrinfo *iterator = NULL, *resolved = NULL; | ||
453 | const char *err = NULL; | ||
454 | int current_family = *family; | ||
455 | /* translate luasocket special values to C */ | ||
456 | if (strcmp(address, "*") == 0) address = NULL; | ||
457 | if (!serv) serv = "0"; | ||
458 | /* try resolving */ | ||
459 | err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); | ||
460 | if (err) { | ||
461 | if (resolved) freeaddrinfo(resolved); | ||
462 | return err; | ||
463 | } | ||
464 | /* iterate over resolved addresses until one is good */ | ||
465 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | ||
466 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { | ||
467 | socket_destroy(ps); | ||
468 | err = inet_trycreate(ps, iterator->ai_family, | ||
469 | iterator->ai_socktype, iterator->ai_protocol); | ||
470 | if (err) continue; | ||
471 | current_family = iterator->ai_family; | ||
472 | } | ||
473 | /* try binding to local address */ | ||
474 | err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, | ||
475 | (socklen_t) iterator->ai_addrlen)); | ||
476 | /* keep trying unless bind succeeded */ | ||
477 | if (err == NULL) { | ||
478 | *family = current_family; | ||
479 | /* set to non-blocking after bind */ | ||
480 | socket_setnonblocking(ps); | ||
481 | break; | ||
482 | } | ||
483 | } | ||
484 | /* cleanup and return error */ | ||
485 | freeaddrinfo(resolved); | ||
486 | /* here, if err is set, we failed */ | ||
487 | return err; | ||
488 | } | ||
489 | |||
490 | /*-------------------------------------------------------------------------*\ | ||
491 | * Some systems do not provide these so that we provide our own. | ||
492 | \*-------------------------------------------------------------------------*/ | ||
493 | #ifdef LUASOCKET_INET_ATON | ||
494 | int inet_aton(const char *cp, struct in_addr *inp) | ||
495 | { | ||
496 | unsigned int a = 0, b = 0, c = 0, d = 0; | ||
497 | int n = 0, r; | ||
498 | unsigned long int addr = 0; | ||
499 | r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); | ||
500 | if (r == 0 || n == 0) return 0; | ||
501 | cp += n; | ||
502 | if (*cp) return 0; | ||
503 | if (a > 255 || b > 255 || c > 255 || d > 255) return 0; | ||
504 | if (inp) { | ||
505 | addr += a; addr <<= 8; | ||
506 | addr += b; addr <<= 8; | ||
507 | addr += c; addr <<= 8; | ||
508 | addr += d; | ||
509 | inp->s_addr = htonl(addr); | ||
510 | } | ||
511 | return 1; | ||
512 | } | ||
513 | #endif | ||
514 | |||
515 | #ifdef LUASOCKET_INET_PTON | ||
516 | int inet_pton(int af, const char *src, void *dst) | ||
517 | { | ||
518 | struct addrinfo hints, *res; | ||
519 | int ret = 1; | ||
520 | memset(&hints, 0, sizeof(struct addrinfo)); | ||
521 | hints.ai_family = af; | ||
522 | hints.ai_flags = AI_NUMERICHOST; | ||
523 | if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1; | ||
524 | if (af == AF_INET) { | ||
525 | struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr; | ||
526 | memcpy(dst, &in->sin_addr, sizeof(in->sin_addr)); | ||
527 | } else if (af == AF_INET6) { | ||
528 | struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr; | ||
529 | memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr)); | ||
530 | } else { | ||
531 | ret = -1; | ||
532 | } | ||
533 | freeaddrinfo(res); | ||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | #endif | ||