beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luasocket / src / inet.c
blob8bad83e7aa16137485e2d541d84908a17927f0df
1 /*=========================================================================*\
2 * Internet domain functions
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <stdio.h>
6 #include <string.h>
8 #include "lua.h"
9 #include "lauxlib.h"
11 #include "inet.h"
13 #if defined(__MINGW32__)
14 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
16 if (af == AF_INET)
18 struct sockaddr_in in;
19 memset(&in, 0, sizeof(in));
20 in.sin_family = AF_INET;
21 memcpy(&in.sin_addr, src, sizeof(struct in_addr));
22 getnameinfo((struct sockaddr *)&in, sizeof(struct
23 sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
24 return dst;
26 else if (af == AF_INET6)
28 struct sockaddr_in6 in;
29 memset(&in, 0, sizeof(in));
30 in.sin6_family = AF_INET6;
31 memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
32 getnameinfo((struct sockaddr *)&in, sizeof(struct
33 sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
34 return dst;
36 return NULL;
39 int inet_pton(int af, const char *src, void *dst)
41 struct addrinfo hints, *res, *ressave;
43 memset(&hints, 0, sizeof(struct addrinfo));
44 hints.ai_family = af;
46 if (getaddrinfo(src, NULL, &hints, &res) != 0)
48 return -1;
51 ressave = res;
53 while (res)
55 memcpy(dst, res->ai_addr, res->ai_addrlen);
56 res = res->ai_next;
59 freeaddrinfo(ressave);
60 return 0;
63 #endif
66 /*=========================================================================*\
67 * Internal function prototypes.
68 \*=========================================================================*/
69 static int inet_global_toip(lua_State *L);
70 static int inet_global_getaddrinfo(lua_State *L);
71 static int inet_global_tohostname(lua_State *L);
72 static int inet_global_getnameinfo(lua_State *L);
73 static void inet_pushresolved(lua_State *L, struct hostent *hp);
74 static int inet_global_gethostname(lua_State *L);
76 /* DNS functions */
77 static luaL_Reg func[] = {
78 { "toip", inet_global_toip},
79 { "getaddrinfo", inet_global_getaddrinfo},
80 { "tohostname", inet_global_tohostname},
81 { "getnameinfo", inet_global_getnameinfo},
82 { "gethostname", inet_global_gethostname},
83 { NULL, NULL}
86 /*=========================================================================*\
87 * Exported functions
88 \*=========================================================================*/
89 /*-------------------------------------------------------------------------*\
90 * Initializes module
91 \*-------------------------------------------------------------------------*/
92 int inet_open(lua_State *L)
94 lua_pushstring(L, "dns");
95 lua_newtable(L);
96 luaL_openlib(L, NULL, func, 0);
97 lua_settable(L, -3);
98 return 0;
101 /*=========================================================================*\
102 * Global Lua functions
103 \*=========================================================================*/
104 /*-------------------------------------------------------------------------*\
105 * Returns all information provided by the resolver given a host name
106 * or ip address
107 \*-------------------------------------------------------------------------*/
108 static int inet_gethost(const char *address, struct hostent **hp) {
109 struct in_addr addr;
110 if (inet_aton(address, &addr))
111 return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
112 else
113 return socket_gethostbyname(address, hp);
116 /*-------------------------------------------------------------------------*\
117 * Returns all information provided by the resolver given a host name
118 * or ip address
119 \*-------------------------------------------------------------------------*/
120 static int inet_global_tohostname(lua_State *L) {
121 const char *address = luaL_checkstring(L, 1);
122 struct hostent *hp = NULL;
123 int err = inet_gethost(address, &hp);
124 if (err != IO_DONE) {
125 lua_pushnil(L);
126 lua_pushstring(L, socket_hoststrerror(err));
127 return 2;
129 lua_pushstring(L, hp->h_name);
130 inet_pushresolved(L, hp);
131 return 2;
134 static int inet_global_getnameinfo(lua_State *L) {
135 int i, ret;
136 char host[1024];
137 char serv[32];
138 struct addrinfo hints;
139 struct addrinfo *resolved, *iter;
140 const char *node = luaL_optstring(L, 1, NULL);
141 const char *service = luaL_optstring(L, 2, NULL);
143 if (!(node || service))
144 luaL_error(L, "You have to specify a hostname, a service, or both");
146 memset(&hints, 0, sizeof(hints));
147 hints.ai_socktype = SOCK_STREAM;
148 hints.ai_family = PF_UNSPEC;
150 /* getaddrinfo must get a node and a service argument */
151 ret = getaddrinfo(node ? node : "127.0.0.1", service ? service : "7",
152 &hints, &resolved);
153 if (ret != 0) {
154 lua_pushnil(L);
155 lua_pushstring(L, socket_gaistrerror(ret));
156 return 2;
159 lua_newtable(L);
160 for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
161 getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, host,
162 node ? (socklen_t) sizeof(host) : 0, serv, service ? (socklen_t) sizeof(serv) : 0, 0);
164 if (node) {
165 lua_pushnumber(L, i);
166 lua_pushstring(L, host);
167 lua_settable(L, -3);
170 freeaddrinfo(resolved);
172 if (service) {
173 lua_pushstring(L, serv);
174 return 2;
175 } else {
176 return 1;
180 /*-------------------------------------------------------------------------*\
181 * Returns all information provided by the resolver given a host name
182 * or ip address
183 \*-------------------------------------------------------------------------*/
184 static int inet_global_toip(lua_State *L)
186 const char *address = luaL_checkstring(L, 1);
187 struct hostent *hp = NULL;
188 int err = inet_gethost(address, &hp);
189 if (err != IO_DONE) {
190 lua_pushnil(L);
191 lua_pushstring(L, socket_hoststrerror(err));
192 return 2;
194 lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
195 inet_pushresolved(L, hp);
196 return 2;
199 int inet_optfamily(lua_State* L, int narg, const char* def)
201 static const char* optname[] = { "unspec", "inet", "inet6", NULL };
202 static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
204 return optvalue[luaL_checkoption(L, narg, def, optname)];
207 int inet_optsocktype(lua_State* L, int narg, const char* def)
209 static const char* optname[] = { "stream", "dgram", NULL };
210 static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
212 return optvalue[luaL_checkoption(L, narg, def, optname)];
215 static int inet_global_getaddrinfo(lua_State *L)
217 const char *hostname = luaL_checkstring(L, 1);
218 struct addrinfo *iterator = NULL, *resolved = NULL;
219 struct addrinfo hints;
220 int i = 1, ret = 0;
221 memset(&hints, 0, sizeof(hints));
222 hints.ai_socktype = SOCK_STREAM;
223 hints.ai_family = PF_UNSPEC;
224 ret = getaddrinfo(hostname, NULL, &hints, &resolved);
225 if (ret != 0) {
226 lua_pushnil(L);
227 lua_pushstring(L, socket_gaistrerror(ret));
228 return 2;
230 lua_newtable(L);
231 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
232 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
233 getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf,
234 (socklen_t) sizeof(hbuf), sbuf, 0, NI_NUMERICHOST);
235 lua_pushnumber(L, i);
236 lua_newtable(L);
237 switch (iterator->ai_family) {
238 case AF_INET:
239 lua_pushliteral(L, "family");
240 lua_pushliteral(L, "inet");
241 lua_settable(L, -3);
242 break;
243 case AF_INET6:
244 lua_pushliteral(L, "family");
245 lua_pushliteral(L, "inet6");
246 lua_settable(L, -3);
247 break;;
249 lua_pushliteral(L, "addr");
250 lua_pushstring(L, hbuf);
251 lua_settable(L, -3);
252 lua_settable(L, -3);
253 i++;
255 freeaddrinfo(resolved);
256 return 1;
260 /*-------------------------------------------------------------------------*\
261 * Gets the host name
262 \*-------------------------------------------------------------------------*/
263 static int inet_global_gethostname(lua_State *L)
265 char name[257];
266 name[256] = '\0';
267 if (gethostname(name, 256) < 0) {
268 lua_pushnil(L);
269 lua_pushstring(L, socket_strerror(errno));
270 return 2;
271 } else {
272 lua_pushstring(L, name);
273 return 1;
279 /*=========================================================================*\
280 * Lua methods
281 \*=========================================================================*/
282 /*-------------------------------------------------------------------------*\
283 * Retrieves socket peer name
284 \*-------------------------------------------------------------------------*/
285 int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
287 switch (family) {
288 case PF_INET: {
289 struct sockaddr_in peer;
290 socklen_t peer_len = sizeof(peer);
291 char name[INET_ADDRSTRLEN];
292 if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
293 lua_pushnil(L);
294 lua_pushstring(L, socket_strerror(errno));
295 return 2;
296 } else {
297 inet_ntop(family, &peer.sin_addr, name, sizeof(name));
298 lua_pushstring(L, name);
299 lua_pushnumber(L, ntohs(peer.sin_port));
300 lua_pushliteral(L, "inet");
301 return 3;
304 case PF_INET6: {
305 struct sockaddr_in6 peer;
306 socklen_t peer_len = sizeof(peer);
307 char name[INET6_ADDRSTRLEN];
308 if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
309 lua_pushnil(L);
310 lua_pushstring(L, socket_strerror(errno));
311 return 2;
312 } else {
313 inet_ntop(family, &peer.sin6_addr, name, sizeof(name));
314 lua_pushstring(L, name);
315 lua_pushnumber(L, ntohs(peer.sin6_port));
316 lua_pushliteral(L, "inet6");
317 return 3;
320 default:
321 lua_pushnil(L);
322 lua_pushfstring(L, "unknown family %d", family);
323 return 2;
327 /*-------------------------------------------------------------------------*\
328 * Retrieves socket local name
329 \*-------------------------------------------------------------------------*/
330 int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
332 switch (family) {
333 case PF_INET: {
334 struct sockaddr_in local;
335 socklen_t local_len = sizeof(local);
336 char name[INET_ADDRSTRLEN];
337 if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
338 lua_pushnil(L);
339 lua_pushstring(L, socket_strerror(errno));
340 return 2;
341 } else {
342 inet_ntop(family, &local.sin_addr, name, sizeof(name));
343 lua_pushstring(L, name);
344 lua_pushnumber(L, ntohs(local.sin_port));
345 lua_pushliteral(L, "inet");
346 return 3;
349 case PF_INET6: {
350 struct sockaddr_in6 local;
351 socklen_t local_len = sizeof(local);
352 char name[INET6_ADDRSTRLEN];
353 if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
354 lua_pushnil(L);
355 lua_pushstring(L, socket_strerror(errno));
356 return 2;
357 } else {
358 inet_ntop(family, &local.sin6_addr, name, sizeof(name));
359 lua_pushstring(L, name);
360 lua_pushnumber(L, ntohs(local.sin6_port));
361 lua_pushliteral(L, "inet6");
362 return 3;
365 default:
366 lua_pushnil(L);
367 lua_pushfstring(L, "unknown family %d", family);
368 return 2;
372 /*=========================================================================*\
373 * Internal functions
374 \*=========================================================================*/
375 /*-------------------------------------------------------------------------*\
376 * Passes all resolver information to Lua as a table
377 \*-------------------------------------------------------------------------*/
378 static void inet_pushresolved(lua_State *L, struct hostent *hp)
380 char **alias;
381 struct in_addr **addr;
382 int i, resolved;
383 lua_newtable(L); resolved = lua_gettop(L);
384 lua_pushstring(L, "name");
385 lua_pushstring(L, hp->h_name);
386 lua_settable(L, resolved);
387 lua_pushstring(L, "ip");
388 lua_pushstring(L, "alias");
389 i = 1;
390 alias = hp->h_aliases;
391 lua_newtable(L);
392 if (alias) {
393 while (*alias) {
394 lua_pushnumber(L, i);
395 lua_pushstring(L, *alias);
396 lua_settable(L, -3);
397 i++; alias++;
400 lua_settable(L, resolved);
401 i = 1;
402 lua_newtable(L);
403 addr = (struct in_addr **) hp->h_addr_list;
404 if (addr) {
405 while (*addr) {
406 lua_pushnumber(L, i);
407 lua_pushstring(L, inet_ntoa(**addr));
408 lua_settable(L, -3);
409 i++; addr++;
412 lua_settable(L, resolved);
415 /*-------------------------------------------------------------------------*\
416 * Tries to create a new inet socket
417 \*-------------------------------------------------------------------------*/
418 const char *inet_trycreate(p_socket ps, int family, int type) {
419 return socket_strerror(socket_create(ps, family, type, 0));
422 /*-------------------------------------------------------------------------*\
423 * "Disconnects" a DGRAM socket
424 \*-------------------------------------------------------------------------*/
425 const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
427 switch (family) {
428 case PF_INET: {
429 struct sockaddr_in sin;
430 memset((char *) &sin, 0, sizeof(sin));
431 sin.sin_family = AF_UNSPEC;
432 sin.sin_addr.s_addr = INADDR_ANY;
433 return socket_strerror(socket_connect(ps, (SA *) &sin,
434 sizeof(sin), tm));
436 case PF_INET6: {
437 struct sockaddr_in6 sin6;
438 struct in6_addr addrany = IN6ADDR_ANY_INIT;
439 memset((char *) &sin6, 0, sizeof(sin6));
440 sin6.sin6_family = AF_UNSPEC;
441 fprintf(stderr, "disconnecting\n");
442 sin6.sin6_addr = addrany;
443 return socket_strerror(socket_connect(ps, (SA *) &sin6,
444 sizeof(sin6), tm));
447 return NULL;
450 /*-------------------------------------------------------------------------*\
451 * Tries to connect to remote address (address, port)
452 \*-------------------------------------------------------------------------*/
453 const char *inet_tryconnect(p_socket ps, const char *address,
454 const char *serv, p_timeout tm, struct addrinfo *connecthints)
456 struct addrinfo *iterator = NULL, *resolved = NULL;
457 const char *err = NULL;
458 /* try resolving */
459 err = socket_gaistrerror(getaddrinfo(address, serv,
460 connecthints, &resolved));
461 if (err != NULL) {
462 if (resolved) freeaddrinfo(resolved);
463 return err;
465 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
466 timeout_markstart(tm);
467 /* try connecting to remote address */
468 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
469 (socklen_t) iterator->ai_addrlen, tm));
470 /* if success, break out of loop */
471 if (err == NULL) break;
473 freeaddrinfo(resolved);
474 /* here, if err is set, we failed */
475 return err;
478 /*-------------------------------------------------------------------------*\
479 * Tries to accept a socket
480 \*-------------------------------------------------------------------------*/
481 const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm)
483 socklen_t len;
484 t_sockaddr_storage addr;
485 if (family == PF_INET6) {
486 len = sizeof(struct sockaddr_in6);
487 } else {
488 len = sizeof(struct sockaddr_in);
490 return socket_strerror(socket_accept(server, client, (SA *) &addr, &len, tm));
493 /*-------------------------------------------------------------------------*\
494 * Tries to bind socket to (address, port)
495 \*-------------------------------------------------------------------------*/
496 const char *inet_trybind(p_socket ps, const char *address, const char *serv,
497 struct addrinfo *bindhints)
499 struct addrinfo *iterator = NULL, *resolved = NULL;
500 const char *err = NULL;
501 t_socket sock = *ps;
502 /* try resolving */
503 err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
504 if (err) {
505 if (resolved) freeaddrinfo(resolved);
506 return err;
508 /* iterate over resolved addresses until one is good */
509 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
510 if(sock == SOCKET_INVALID) {
511 err = socket_strerror(socket_create(&sock, iterator->ai_family,
512 iterator->ai_socktype, iterator->ai_protocol));
513 if(err)
514 continue;
516 /* try binding to local address */
517 err = socket_strerror(socket_bind(&sock,
518 (SA *) iterator->ai_addr,
519 (socklen_t) iterator->ai_addrlen));
521 /* keep trying unless bind succeeded */
522 if (err) {
523 if(sock != *ps)
524 socket_destroy(&sock);
525 } else {
526 /* remember what we connected to, particularly the family */
527 *bindhints = *iterator;
528 break;
531 /* cleanup and return error */
532 freeaddrinfo(resolved);
533 *ps = sock;
534 return err;
537 /*-------------------------------------------------------------------------*\
538 * Some systems do not provide this so that we provide our own. It's not
539 * marvelously fast, but it works just fine.
540 \*-------------------------------------------------------------------------*/
541 #ifdef INET_ATON
542 int inet_aton(const char *cp, struct in_addr *inp)
544 unsigned int a = 0, b = 0, c = 0, d = 0;
545 int n = 0, r;
546 unsigned long int addr = 0;
547 r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
548 if (r == 0 || n == 0) return 0;
549 cp += n;
550 if (*cp) return 0;
551 if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
552 if (inp) {
553 addr += a; addr <<= 8;
554 addr += b; addr <<= 8;
555 addr += c; addr <<= 8;
556 addr += d;
557 inp->s_addr = htonl(addr);
559 return 1;
561 #endif