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>
28 * getaddrinfo(host, family, port)
30 static int nixio_getaddrinfo(lua_State
*L
) {
31 const char *host
= NULL
;
32 if (!lua_isnoneornil(L
, 1)) {
33 host
= luaL_checklstring(L
, 1, NULL
);
35 const char *family
= luaL_optlstring(L
, 2, "any", NULL
);
36 const char *port
= lua_tolstring(L
, 3, NULL
);
38 struct addrinfo hints
, *result
, *rp
;
39 memset(&hints
, 0, sizeof(hints
));
41 if (!strcmp(family
, "any")) {
42 hints
.ai_family
= AF_UNSPEC
;
43 } else if (!strcmp(family
, "inet")) {
44 hints
.ai_family
= AF_INET
;
45 } else if (!strcmp(family
, "inet6")) {
46 hints
.ai_family
= AF_INET6
;
48 return luaL_argerror(L
, 2, "supported values: any, inet, inet6");
51 hints
.ai_socktype
= 0;
52 hints
.ai_protocol
= 0;
54 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
57 lua_pushinteger(L
, aistat
);
58 lua_pushstring(L
, gai_strerror(aistat
));
62 /* create socket object */
66 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
67 /* avoid duplicate results */
68 if (!port
&& rp
->ai_socktype
!= SOCK_STREAM
) {
72 if (rp
->ai_family
== AF_INET
|| rp
->ai_family
== AF_INET6
) {
73 lua_createtable(L
, 0, port
? 4 : 2);
74 if (rp
->ai_family
== AF_INET
) {
75 lua_pushliteral(L
, "inet");
76 } else if (rp
->ai_family
== AF_INET6
) {
77 lua_pushliteral(L
, "inet6");
79 lua_setfield(L
, -2, "family");
82 switch (rp
->ai_socktype
) {
84 lua_pushliteral(L
, "stream");
87 lua_pushliteral(L
, "dgram");
90 lua_pushliteral(L
, "raw");
96 lua_setfield(L
, -2, "socktype");
99 char ip
[INET6_ADDRSTRLEN
];
100 void *binaddr
= NULL
;
101 uint16_t binport
= 0;
103 if (rp
->ai_family
== AF_INET
) {
104 struct sockaddr_in
*v4addr
= (struct sockaddr_in
*)rp
->ai_addr
;
105 binport
= v4addr
->sin_port
;
106 binaddr
= (void *)&v4addr
->sin_addr
;
107 } else if (rp
->ai_family
== AF_INET6
) {
108 struct sockaddr_in6
*v6addr
= (struct sockaddr_in6
*)rp
->ai_addr
;
109 binport
= v6addr
->sin6_port
;
110 binaddr
= (void *)&v6addr
->sin6_addr
;
113 if (!inet_ntop(rp
->ai_family
, binaddr
, ip
, sizeof(ip
))) {
114 freeaddrinfo(result
);
115 return nixio__perror(L
);
119 lua_pushinteger(L
, ntohs(binport
));
120 lua_setfield(L
, -2, "port");
123 lua_pushstring(L
, ip
);
124 lua_setfield(L
, -2, "address");
125 lua_rawseti(L
, -2, i
++);
129 freeaddrinfo(result
);
135 * getnameinfo(address, family)
137 static int nixio_getnameinfo(lua_State
*L
) {
138 const char *ip
= luaL_checklstring(L
, 1, NULL
);
139 const char *family
= luaL_optlstring(L
, 2, "inet", NULL
);
140 char host
[NI_MAXHOST
];
142 struct sockaddr
*addr
= NULL
;
146 if (!strcmp(family
, "inet")) {
147 struct sockaddr_in inetaddr
;
148 memset(&inetaddr
, 0, sizeof(inetaddr
));
149 inetaddr
.sin_family
= AF_INET
;
150 if (inet_pton(AF_INET
, ip
, &inetaddr
.sin_addr
) < 1) {
151 return luaL_argerror(L
, 1, "invalid address");
153 alen
= sizeof(inetaddr
);
154 addr
= (struct sockaddr
*)&inetaddr
;
155 } else if (!strcmp(family
, "inet6")) {
156 struct sockaddr_in6 inet6addr
;
157 memset(&inet6addr
, 0, sizeof(inet6addr
));
158 inet6addr
.sin6_family
= AF_INET6
;
159 if (inet_pton(AF_INET6
, ip
, &inet6addr
.sin6_addr
) < 1) {
160 return luaL_argerror(L
, 1, "invalid address");
162 alen
= sizeof(inet6addr
);
163 addr
= (struct sockaddr
*)&inet6addr
;
165 return luaL_argerror(L
, 2, "supported values: inet, inet6");
168 res
= getnameinfo(addr
, alen
, host
, sizeof(host
), NULL
, 0, NI_NAMEREQD
);
171 lua_pushinteger(L
, res
);
172 lua_pushstring(L
, gai_strerror(res
));
175 lua_pushstring(L
, host
);
181 * getsockname() / getpeername() helper
183 static int nixio_sock__getname(lua_State
*L
, int sock
) {
184 int sockfd
= nixio__checksockfd(L
);
185 struct sockaddr_storage addr
;
186 socklen_t addrlen
= sizeof(addr
);
187 char ipaddr
[INET6_ADDRSTRLEN
];
192 if (getsockname(sockfd
, (struct sockaddr
*)&addr
, &addrlen
)) {
193 return nixio__perror(L
);
196 if (getpeername(sockfd
, (struct sockaddr
*)&addr
, &addrlen
)) {
197 return nixio__perror(L
);
201 if (addr
.ss_family
== AF_INET
) {
202 struct sockaddr_in
*inetaddr
= (struct sockaddr_in
*)&addr
;
203 port
= inetaddr
->sin_port
;
204 binaddr
= &inetaddr
->sin_addr
;
205 } else if (addr
.ss_family
== AF_INET6
) {
206 struct sockaddr_in6
*inet6addr
= (struct sockaddr_in6
*)&addr
;
207 port
= inet6addr
->sin6_port
;
208 binaddr
= &inet6addr
->sin6_addr
;
210 return luaL_error(L
, "unknown address family");
213 if (!inet_ntop(addr
.ss_family
, binaddr
, ipaddr
, sizeof(ipaddr
))) {
214 return nixio__perror(L
);
217 lua_pushstring(L
, ipaddr
);
218 lua_pushinteger(L
, ntohs(port
));
225 static int nixio_sock_getsockname(lua_State
*L
) {
226 return nixio_sock__getname(L
, 1);
232 static int nixio_sock_getpeername(lua_State
*L
) {
233 return nixio_sock__getname(L
, 0);
238 static const luaL_reg R
[] = {
239 {"getaddrinfo", nixio_getaddrinfo
},
240 {"getnameinfo", nixio_getnameinfo
},
245 static const luaL_reg M
[] = {
246 {"getsockname", nixio_sock_getsockname
},
247 {"getpeername", nixio_sock_getpeername
},
251 void nixio_open_address(lua_State
*L
) {
252 luaL_register(L
, NULL
, R
);
254 lua_pushvalue(L
, -2);
255 luaL_register(L
, NULL
, M
);