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.
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <arpa/inet.h>
30 * getaddrinfo(host, family, port)
32 static int nixio_getaddrinfo(lua_State *L) {
33 const char *host = NULL;
34 if (!lua_isnoneornil(L, 1)) {
35 host = luaL_checklstring(L, 1, NULL);
37 const char *family = luaL_optlstring(L, 2, "any", NULL);
38 const char *port = lua_tolstring(L, 3, NULL);
40 struct addrinfo hints, *result, *rp;
41 memset(&hints, 0, sizeof(hints));
43 if (!strcmp(family, "any")) {
44 hints.ai_family = AF_UNSPEC;
45 } else if (!strcmp(family, "inet")) {
46 hints.ai_family = AF_INET;
47 } else if (!strcmp(family, "inet6")) {
48 hints.ai_family = AF_INET6;
50 return luaL_argerror(L, 2, "supported values: any, inet, inet6");
53 hints.ai_socktype = 0;
54 hints.ai_protocol = 0;
56 int aistat = getaddrinfo(host, port, &hints, &result);
59 lua_pushinteger(L, aistat);
60 lua_pushstring(L, gai_strerror(aistat));
64 /* create socket object */
68 for (rp = result; rp != NULL; rp = rp->ai_next) {
69 /* avoid duplicate results */
70 if (!port && rp->ai_socktype != SOCK_STREAM) {
74 if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) {
75 lua_createtable(L, 0, port ? 4 : 2);
76 if (rp->ai_family == AF_INET) {
77 lua_pushliteral(L, "inet");
78 } else if (rp->ai_family == AF_INET6) {
79 lua_pushliteral(L, "inet6");
81 lua_setfield(L, -2, "family");
84 switch (rp->ai_socktype) {
86 lua_pushliteral(L, "stream");
89 lua_pushliteral(L, "dgram");
92 lua_pushliteral(L, "raw");
98 lua_setfield(L, -2, "socktype");
101 char ip[INET6_ADDRSTRLEN];
102 void *binaddr = NULL;
103 uint16_t binport = 0;
105 if (rp->ai_family == AF_INET) {
106 struct sockaddr_in *v4addr = (struct sockaddr_in*)rp->ai_addr;
107 binport = v4addr->sin_port;
108 binaddr = (void *)&v4addr->sin_addr;
109 } else if (rp->ai_family == AF_INET6) {
110 struct sockaddr_in6 *v6addr = (struct sockaddr_in6*)rp->ai_addr;
111 binport = v6addr->sin6_port;
112 binaddr = (void *)&v6addr->sin6_addr;
115 if (!inet_ntop(rp->ai_family, binaddr, ip, sizeof(ip))) {
116 freeaddrinfo(result);
117 return nixio__perror(L);
121 lua_pushinteger(L, ntohs(binport));
122 lua_setfield(L, -2, "port");
125 lua_pushstring(L, ip);
126 lua_setfield(L, -2, "address");
127 lua_rawseti(L, -2, i++);
131 freeaddrinfo(result);
137 * getnameinfo(address, family)
139 static int nixio_getnameinfo(lua_State *L) {
140 const char *ip = luaL_checklstring(L, 1, NULL);
141 const char *family = luaL_optlstring(L, 2, "inet", NULL);
142 char host[NI_MAXHOST];
144 struct sockaddr *addr = NULL;
148 if (!strcmp(family, "inet")) {
149 struct sockaddr_in inetaddr;
150 memset(&inetaddr, 0, sizeof(inetaddr));
151 inetaddr.sin_family = AF_INET;
152 if (inet_pton(AF_INET, ip, &inetaddr.sin_addr) < 1) {
153 return luaL_argerror(L, 1, "invalid address");
155 alen = sizeof(inetaddr);
156 addr = (struct sockaddr *)&inetaddr;
157 } else if (!strcmp(family, "inet6")) {
158 struct sockaddr_in6 inet6addr;
159 memset(&inet6addr, 0, sizeof(inet6addr));
160 inet6addr.sin6_family = AF_INET6;
161 if (inet_pton(AF_INET6, ip, &inet6addr.sin6_addr) < 1) {
162 return luaL_argerror(L, 1, "invalid address");
164 alen = sizeof(inet6addr);
165 addr = (struct sockaddr *)&inet6addr;
167 return luaL_argerror(L, 2, "supported values: inet, inet6");
170 res = getnameinfo(addr, alen, host, sizeof(host), NULL, 0, NI_NAMEREQD);
173 lua_pushinteger(L, res);
174 lua_pushstring(L, gai_strerror(res));
177 lua_pushstring(L, host);
183 * getsockname() / getpeername() helper
185 static int nixio_sock__getname(lua_State *L, int sock) {
186 int sockfd = nixio__checksockfd(L);
187 struct sockaddr_storage addr;
188 socklen_t addrlen = sizeof(addr);
189 char ipaddr[INET6_ADDRSTRLEN];
194 if (getsockname(sockfd, (struct sockaddr*)&addr, &addrlen)) {
195 return nixio__perror(L);
198 if (getpeername(sockfd, (struct sockaddr*)&addr, &addrlen)) {
199 return nixio__perror(L);
203 if (addr.ss_family == AF_INET) {
204 struct sockaddr_in *inetaddr = (struct sockaddr_in*)&addr;
205 port = inetaddr->sin_port;
206 binaddr = &inetaddr->sin_addr;
207 } else if (addr.ss_family == AF_INET6) {
208 struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)&addr;
209 port = inet6addr->sin6_port;
210 binaddr = &inet6addr->sin6_addr;
212 return luaL_error(L, "unknown address family");
215 if (!inet_ntop(addr.ss_family, binaddr, ipaddr, sizeof(ipaddr))) {
216 return nixio__perror(L);
219 lua_pushstring(L, ipaddr);
220 lua_pushinteger(L, ntohs(port));
227 static int nixio_sock_getsockname(lua_State *L) {
228 return nixio_sock__getname(L, 1);
234 static int nixio_sock_getpeername(lua_State *L) {
235 return nixio_sock__getname(L, 0);
240 static const luaL_reg R[] = {
241 {"getaddrinfo", nixio_getaddrinfo},
242 {"getnameinfo", nixio_getnameinfo},
247 static const luaL_reg M[] = {
248 {"getsockname", nixio_sock_getsockname},
249 {"getpeername", nixio_sock_getpeername},
253 void nixio_open_address(lua_State *L) {
254 luaL_register(L, NULL, R);
256 lua_pushvalue(L, -2);
257 luaL_register(L, NULL, M);