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>
25 #define NI_MAXHOST 1025
29 * address pushing helper
31 int nixio__addr_parse(nixio_addr *addr, struct sockaddr *saddr) {
34 addr->family = saddr->sa_family;
35 if (saddr->sa_family == AF_INET) {
36 struct sockaddr_in *inetaddr = (struct sockaddr_in*)saddr;
37 addr->port = ntohs(inetaddr->sin_port);
38 baddr = &inetaddr->sin_addr;
39 } else if (saddr->sa_family == AF_INET6) {
40 struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)saddr;
41 addr->port = ntohs(inet6addr->sin6_port);
42 baddr = &inet6addr->sin6_addr;
48 if (!inet_ntop(saddr->sa_family, baddr, addr->host, sizeof(addr->host))) {
56 * address pulling helper
58 int nixio__addr_write(nixio_addr *addr, struct sockaddr *saddr) {
59 if (addr->family == AF_UNSPEC) {
60 if (strchr(addr->host, ':')) {
61 addr->family = AF_INET6;
63 addr->family = AF_INET;
66 if (addr->family == AF_INET) {
67 struct sockaddr_in *inetaddr = (struct sockaddr_in *)saddr;
68 memset(inetaddr, 0, sizeof(struct sockaddr_in));
70 if (inet_pton(AF_INET, addr->host, &inetaddr->sin_addr) < 1) {
74 inetaddr->sin_family = AF_INET;
75 inetaddr->sin_port = htons((uint16_t)addr->port);
77 } else if (addr->family == AF_INET6) {
78 struct sockaddr_in6 *inet6addr = (struct sockaddr_in6 *)saddr;
79 memset(inet6addr, 0, sizeof(struct sockaddr_in6));
81 if (inet_pton(AF_INET6, addr->host, &inet6addr->sin6_addr) < 1) {
85 inet6addr->sin6_family = AF_INET6;
86 inet6addr->sin6_port = htons((uint16_t)addr->port);
96 * getaddrinfo(host, family, port)
98 static int nixio_getaddrinfo(lua_State *L) {
99 const char *host = NULL;
100 if (!lua_isnoneornil(L, 1)) {
101 host = luaL_checklstring(L, 1, NULL);
103 const char *family = luaL_optlstring(L, 2, "any", NULL);
104 const char *port = lua_tolstring(L, 3, NULL);
106 struct addrinfo hints, *result, *rp;
107 memset(&hints, 0, sizeof(hints));
109 if (!strcmp(family, "any")) {
110 hints.ai_family = AF_UNSPEC;
111 } else if (!strcmp(family, "inet")) {
112 hints.ai_family = AF_INET;
113 } else if (!strcmp(family, "inet6")) {
114 hints.ai_family = AF_INET6;
116 return luaL_argerror(L, 2, "supported values: any, inet, inet6");
119 hints.ai_socktype = 0;
120 hints.ai_protocol = 0;
122 int aistat = getaddrinfo(host, port, &hints, &result);
125 lua_pushinteger(L, aistat);
126 lua_pushstring(L, gai_strerror(aistat));
130 /* create socket object */
134 for (rp = result; rp != NULL; rp = rp->ai_next) {
135 /* avoid duplicate results */
137 if (!port && rp->ai_socktype != SOCK_STREAM) {
142 if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) {
143 lua_createtable(L, 0, port ? 4 : 2);
144 if (rp->ai_family == AF_INET) {
145 lua_pushliteral(L, "inet");
146 } else if (rp->ai_family == AF_INET6) {
147 lua_pushliteral(L, "inet6");
149 lua_setfield(L, -2, "family");
152 switch (rp->ai_socktype) {
154 lua_pushliteral(L, "stream");
157 lua_pushliteral(L, "dgram");
160 lua_pushliteral(L, "raw");
166 lua_setfield(L, -2, "socktype");
170 if (nixio__addr_parse(&addr, rp->ai_addr)) {
171 freeaddrinfo(result);
172 return nixio__perror_s(L);
176 lua_pushinteger(L, addr.port);
177 lua_setfield(L, -2, "port");
180 lua_pushstring(L, addr.host);
181 lua_setfield(L, -2, "address");
182 lua_rawseti(L, -2, i++);
186 freeaddrinfo(result);
192 * getnameinfo(address, family)
194 static int nixio_getnameinfo(lua_State *L) {
195 const char *ip = luaL_checkstring(L, 1);
196 const char *family = luaL_optstring(L, 2, NULL);
197 char host[NI_MAXHOST];
199 struct sockaddr_storage saddr;
201 memset(&addr, 0, sizeof(addr));
202 strncpy(addr.host, ip, sizeof(addr.host) - 1);
205 addr.family = AF_UNSPEC;
206 } else if (!strcmp(family, "inet")) {
207 addr.family = AF_INET;
208 } else if (!strcmp(family, "inet6")) {
209 addr.family = AF_INET6;
211 return luaL_argerror(L, 2, "supported values: inet, inet6");
214 nixio__addr_write(&addr, (struct sockaddr *)&saddr);
216 int res = getnameinfo((struct sockaddr *)&saddr, sizeof(saddr),
217 host, sizeof(host), NULL, 0, NI_NAMEREQD);
220 lua_pushinteger(L, res);
221 lua_pushstring(L, gai_strerror(res));
224 lua_pushstring(L, host);
232 static int nixio_sock_getsockname(lua_State *L) {
233 int sockfd = nixio__checksockfd(L);
234 struct sockaddr_storage saddr;
235 socklen_t addrlen = sizeof(saddr);
238 if (getsockname(sockfd, (struct sockaddr*)&saddr, &addrlen) ||
239 nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) {
240 return nixio__perror_s(L);
243 lua_pushstring(L, addr.host);
244 lua_pushnumber(L, addr.port);
251 static int nixio_sock_getpeername(lua_State *L) {
252 int sockfd = nixio__checksockfd(L);
253 struct sockaddr_storage saddr;
254 socklen_t addrlen = sizeof(saddr);
257 if (getpeername(sockfd, (struct sockaddr*)&saddr, &addrlen) ||
258 nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) {
259 return nixio__perror_s(L);
262 lua_pushstring(L, addr.host);
263 lua_pushnumber(L, addr.port);
269 static const luaL_reg R[] = {
270 {"getaddrinfo", nixio_getaddrinfo},
271 {"getnameinfo", nixio_getnameinfo},
276 static const luaL_reg M[] = {
277 {"getsockname", nixio_sock_getsockname},
278 {"getpeername", nixio_sock_getpeername},
282 void nixio_open_address(lua_State *L) {
283 luaL_register(L, NULL, R);
285 lua_pushvalue(L, -2);
286 luaL_register(L, NULL, M);