2 * nixio - Linux I/O library for lua
4 * Copyright (C) 2009 Steven Barth <steven@midlink.org>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <arpa/inet.h>
27 #define NI_MAXHOST 1025
32 * getaddrinfo(host, family, port)
34 static int nixio_getaddrinfo(lua_State
*L
) {
35 const char *host
= NULL
;
36 if (!lua_isnoneornil(L
, 1)) {
37 host
= luaL_checklstring(L
, 1, NULL
);
39 const char *family
= luaL_optlstring(L
, 2, "any", NULL
);
40 const char *port
= lua_tolstring(L
, 3, NULL
);
42 struct addrinfo hints
, *result
, *rp
;
43 memset(&hints
, 0, sizeof(hints
));
45 if (!strcmp(family
, "any")) {
46 hints
.ai_family
= AF_UNSPEC
;
47 } else if (!strcmp(family
, "inet")) {
48 hints
.ai_family
= AF_INET
;
49 } else if (!strcmp(family
, "inet6")) {
50 hints
.ai_family
= AF_INET6
;
52 return luaL_argerror(L
, 2, "supported values: any, inet, inet6");
55 hints
.ai_socktype
= 0;
56 hints
.ai_protocol
= 0;
58 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
61 lua_pushinteger(L
, aistat
);
62 lua_pushstring(L
, gai_strerror(aistat
));
66 /* create socket object */
70 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
71 /* avoid duplicate results */
72 if (!port
&& rp
->ai_socktype
!= SOCK_STREAM
) {
76 if (rp
->ai_family
== AF_INET
|| rp
->ai_family
== AF_INET6
) {
77 lua_createtable(L
, 0, port
? 4 : 2);
78 if (rp
->ai_family
== AF_INET
) {
79 lua_pushliteral(L
, "inet");
80 } else if (rp
->ai_family
== AF_INET6
) {
81 lua_pushliteral(L
, "inet6");
83 lua_setfield(L
, -2, "family");
86 switch (rp
->ai_socktype
) {
88 lua_pushliteral(L
, "stream");
91 lua_pushliteral(L
, "dgram");
94 lua_pushliteral(L
, "raw");
100 lua_setfield(L
, -2, "socktype");
103 char ip
[INET6_ADDRSTRLEN
];
104 void *binaddr
= NULL
;
105 uint16_t binport
= 0;
107 if (rp
->ai_family
== AF_INET
) {
108 struct sockaddr_in
*v4addr
= (struct sockaddr_in
*)rp
->ai_addr
;
109 binport
= v4addr
->sin_port
;
110 binaddr
= (void *)&v4addr
->sin_addr
;
111 } else if (rp
->ai_family
== AF_INET6
) {
112 struct sockaddr_in6
*v6addr
= (struct sockaddr_in6
*)rp
->ai_addr
;
113 binport
= v6addr
->sin6_port
;
114 binaddr
= (void *)&v6addr
->sin6_addr
;
117 if (!inet_ntop(rp
->ai_family
, binaddr
, ip
, sizeof(ip
))) {
118 freeaddrinfo(result
);
119 return nixio__perror(L
);
123 lua_pushinteger(L
, ntohs(binport
));
124 lua_setfield(L
, -2, "port");
127 lua_pushstring(L
, ip
);
128 lua_setfield(L
, -2, "address");
129 lua_rawseti(L
, -2, i
++);
133 freeaddrinfo(result
);
139 * getnameinfo(address, family)
141 static int nixio_getnameinfo(lua_State
*L
) {
142 const char *ip
= luaL_checklstring(L
, 1, NULL
);
143 const char *family
= luaL_optlstring(L
, 2, "inet", NULL
);
144 char host
[NI_MAXHOST
];
146 struct sockaddr
*addr
= NULL
;
150 if (!strcmp(family
, "inet")) {
151 struct sockaddr_in inetaddr
;
152 memset(&inetaddr
, 0, sizeof(inetaddr
));
153 inetaddr
.sin_family
= AF_INET
;
154 if (inet_pton(AF_INET
, ip
, &inetaddr
.sin_addr
) < 1) {
155 return luaL_argerror(L
, 1, "invalid address");
157 alen
= sizeof(inetaddr
);
158 addr
= (struct sockaddr
*)&inetaddr
;
159 } else if (!strcmp(family
, "inet6")) {
160 struct sockaddr_in6 inet6addr
;
161 memset(&inet6addr
, 0, sizeof(inet6addr
));
162 inet6addr
.sin6_family
= AF_INET6
;
163 if (inet_pton(AF_INET6
, ip
, &inet6addr
.sin6_addr
) < 1) {
164 return luaL_argerror(L
, 1, "invalid address");
166 alen
= sizeof(inet6addr
);
167 addr
= (struct sockaddr
*)&inet6addr
;
169 return luaL_argerror(L
, 2, "supported values: inet, inet6");
172 res
= getnameinfo(addr
, alen
, host
, sizeof(host
), NULL
, 0, NI_NAMEREQD
);
175 lua_pushinteger(L
, res
);
176 lua_pushstring(L
, gai_strerror(res
));
179 lua_pushstring(L
, host
);
185 * getsockname() / getpeername() helper
187 static int nixio_sock__getname(lua_State
*L
, int sock
) {
188 int sockfd
= nixio__checksockfd(L
);
189 struct sockaddr_storage addr
;
190 socklen_t addrlen
= sizeof(addr
);
191 char ipaddr
[INET6_ADDRSTRLEN
];
196 if (getsockname(sockfd
, (struct sockaddr
*)&addr
, &addrlen
)) {
197 return nixio__perror(L
);
200 if (getpeername(sockfd
, (struct sockaddr
*)&addr
, &addrlen
)) {
201 return nixio__perror(L
);
205 if (addr
.ss_family
== AF_INET
) {
206 struct sockaddr_in
*inetaddr
= (struct sockaddr_in
*)&addr
;
207 port
= inetaddr
->sin_port
;
208 binaddr
= &inetaddr
->sin_addr
;
209 } else if (addr
.ss_family
== AF_INET6
) {
210 struct sockaddr_in6
*inet6addr
= (struct sockaddr_in6
*)&addr
;
211 port
= inet6addr
->sin6_port
;
212 binaddr
= &inet6addr
->sin6_addr
;
214 return luaL_error(L
, "unknown address family");
217 if (!inet_ntop(addr
.ss_family
, binaddr
, ipaddr
, sizeof(ipaddr
))) {
218 return nixio__perror(L
);
221 lua_pushstring(L
, ipaddr
);
222 lua_pushinteger(L
, ntohs(port
));
229 static int nixio_sock_getsockname(lua_State
*L
) {
230 return nixio_sock__getname(L
, 1);
236 static int nixio_sock_getpeername(lua_State
*L
) {
237 return nixio_sock__getname(L
, 0);
242 static const luaL_reg R
[] = {
243 {"getaddrinfo", nixio_getaddrinfo
},
244 {"getnameinfo", nixio_getnameinfo
},
249 static const luaL_reg M
[] = {
250 {"getsockname", nixio_sock_getsockname
},
251 {"getpeername", nixio_sock_getpeername
},
255 void nixio_open_address(lua_State
*L
) {
256 luaL_register(L
, NULL
, R
);
258 lua_pushvalue(L
, -2);
259 luaL_register(L
, NULL
, M
);