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>
30 * connect()/bind() shortcut
32 static int nixio__bind_connect(lua_State
*L
, int do_bind
) {
33 const char *host
= NULL
;
34 if (!lua_isnoneornil(L
, 1)) {
35 host
= luaL_checklstring(L
, 1, NULL
);
37 const char *port
= luaL_checklstring(L
, 2, NULL
);
38 const char *family
= luaL_optlstring(L
, 3, "any", NULL
);
39 const char *socktype
= luaL_optlstring(L
, 4, "stream", NULL
);
41 struct addrinfo hints
, *result
, *rp
;
42 memset(&hints
, 0, sizeof(hints
));
44 if (!strcmp(family
, "any")) {
45 hints
.ai_family
= AF_UNSPEC
;
46 } else if (!strcmp(family
, "inet")) {
47 hints
.ai_family
= AF_INET
;
48 } else if (!strcmp(family
, "inet6")) {
49 hints
.ai_family
= AF_INET6
;
51 return luaL_argerror(L
, 3, "supported values: any, inet, inet6");
54 if (!strcmp(socktype
, "any")) {
55 hints
.ai_socktype
= 0;
56 } else if (!strcmp(socktype
, "stream")) {
57 hints
.ai_socktype
= SOCK_STREAM
;
58 } else if (!strcmp(socktype
, "dgram")) {
59 hints
.ai_socktype
= SOCK_DGRAM
;
61 return luaL_argerror(L
, 4, "supported values: any, stream, dgram");
65 hints
.ai_flags
|= AI_PASSIVE
;
68 hints
.ai_protocol
= 0;
70 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
73 lua_pushinteger(L
, aistat
);
74 lua_pushstring(L
, gai_strerror(aistat
));
78 /* create socket object */
79 nixio_sock
*sock
= lua_newuserdata(L
, sizeof(nixio_sock
));
82 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
83 sock
->fd
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
);
89 status
= bind(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
91 status
= connect(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
96 sock
->domain
= rp
->ai_family
;
97 sock
->type
= rp
->ai_socktype
;
98 sock
->protocol
= rp
->ai_protocol
;
105 freeaddrinfo(result
);
109 return nixio__perror(L
);
112 luaL_getmetatable(L
, NIXIO_META
);
113 lua_setmetatable(L
, -2);
119 * bind(host, port, [family=any], [type=any]) shortcut
121 static int nixio_bind(lua_State
*L
) {
122 return nixio__bind_connect(L
, 1);
126 * connect(host, port, [family=any], [type=any]) shortcut
128 static int nixio_connect(lua_State
*L
) {
129 return nixio__bind_connect(L
, 0);
133 * bind()/connect() helper
135 static int nixio_sock__bind_connect(lua_State
*L
, int do_bind
) {
136 nixio_sock
*sock
= nixio__checksock(L
);
139 if (sock
->domain
== AF_INET
|| sock
->domain
== AF_INET6
) {
140 const char *host
= NULL
;
141 if (!lua_isnoneornil(L
, 2)) {
142 host
= luaL_checklstring(L
, 2, NULL
);
144 const char *port
= luaL_checklstring(L
, 3, NULL
);
146 struct addrinfo hints
, *result
, *rp
;
148 memset(&hints
, 0, sizeof(hints
));
149 hints
.ai_family
= sock
->domain
;
150 hints
.ai_socktype
= sock
->type
;
151 hints
.ai_protocol
= sock
->protocol
;
154 hints
.ai_flags
|= AI_PASSIVE
;
157 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
160 lua_pushinteger(L
, aistat
);
161 lua_pushstring(L
, gai_strerror(aistat
));
165 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
167 status
= bind(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
169 status
= connect(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
178 freeaddrinfo(result
);
179 } else if (sock
->domain
== AF_UNIX
) {
181 const char *path
= luaL_checklstring(L
, 2, &pathlen
);
183 struct sockaddr_un addr
;
184 addr
.sun_family
= AF_UNIX
;
185 luaL_argcheck(L
, pathlen
< sizeof(addr
.sun_path
), 2, "out of range");
186 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
));
189 status
= bind(sock
->fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
191 status
= connect(sock
->fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
194 return luaL_error(L
, "not supported");
196 return nixio__pstatus(L
, !status
);
202 static int nixio_sock_bind(lua_State
*L
) {
203 return nixio_sock__bind_connect(L
, 1);
209 static int nixio_sock_connect(lua_State
*L
) {
210 return nixio_sock__bind_connect(L
, 0);
216 static int nixio_sock_listen(lua_State
*L
) {
217 int sockfd
= nixio__checksockfd(L
);
218 lua_Integer backlog
= luaL_checkinteger(L
, 2);
219 return nixio__pstatus(L
, !listen(sockfd
, backlog
));
225 static int nixio_sock_accept(lua_State
*L
) {
226 nixio_sock
*sock
= nixio__checksock(L
);
227 struct sockaddr_storage addr
;
228 socklen_t addrlen
= sizeof(addr
);
229 char ipaddr
[INET6_ADDRSTRLEN
];
233 int newfd
= accept(sock
->fd
, (struct sockaddr
*)&addr
, &addrlen
);
235 return nixio__perror(L
);
238 /* create userdata */
239 nixio_sock
*clsock
= lua_newuserdata(L
, sizeof(nixio_sock
));
240 luaL_getmetatable(L
, NIXIO_META
);
241 lua_setmetatable(L
, -2);
243 memcpy(clsock
, sock
, sizeof(clsock
));
246 if (addr
.ss_family
== AF_INET
) {
247 struct sockaddr_in
*inetaddr
= (struct sockaddr_in
*)&addr
;
248 port
= inetaddr
->sin_port
;
249 binaddr
= &inetaddr
->sin_addr
;
250 } else if (addr
.ss_family
== AF_INET6
) {
251 struct sockaddr_in6
*inet6addr
= (struct sockaddr_in6
*)&addr
;
252 port
= inet6addr
->sin6_port
;
253 binaddr
= &inet6addr
->sin6_addr
;
255 return luaL_error(L
, "unknown address family");
258 if (!inet_ntop(addr
.ss_family
, binaddr
, ipaddr
, sizeof(ipaddr
))) {
259 return nixio__perror(L
);
262 lua_pushstring(L
, ipaddr
);
263 lua_pushinteger(L
, ntohs(port
));
268 static const luaL_reg R
[] = {
269 {"bind", nixio_bind
},
270 {"connect", nixio_connect
},
275 static const luaL_reg M
[] = {
276 {"bind", nixio_sock_bind
},
277 {"connect", nixio_sock_connect
},
278 {"listen", nixio_sock_listen
},
279 {"accept", nixio_sock_accept
},
283 void nixio_open_bind(lua_State
*L
) {
284 luaL_register(L
, NULL
, R
);
286 lua_pushvalue(L
, -2);
287 luaL_register(L
, NULL
, M
);