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>
27 * connect()/bind() shortcut
29 static int nixio__bind_connect(lua_State
*L
, int do_bind
) {
30 const char *host
= NULL
;
31 if (!lua_isnoneornil(L
, 1)) {
32 host
= luaL_checklstring(L
, 1, NULL
);
34 const char *port
= luaL_checklstring(L
, 2, NULL
);
35 const char *family
= luaL_optlstring(L
, 3, "any", NULL
);
36 const char *socktype
= luaL_optlstring(L
, 4, "stream", 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
, 3, "supported values: any, inet, inet6");
51 if (!strcmp(socktype
, "any")) {
52 hints
.ai_socktype
= 0;
53 } else if (!strcmp(socktype
, "stream")) {
54 hints
.ai_socktype
= SOCK_STREAM
;
55 } else if (!strcmp(socktype
, "dgram")) {
56 hints
.ai_socktype
= SOCK_DGRAM
;
58 return luaL_argerror(L
, 4, "supported values: any, stream, dgram");
62 hints
.ai_flags
|= AI_PASSIVE
;
65 hints
.ai_protocol
= 0;
67 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
70 lua_pushinteger(L
, aistat
);
71 lua_pushstring(L
, gai_strerror(aistat
));
75 /* create socket object */
76 nixio_sock
*sock
= lua_newuserdata(L
, sizeof(nixio_sock
));
77 int status
= -1, clstat
;
79 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
80 sock
->fd
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
);
87 setsockopt(sock
->fd
, SOL_SOCKET
, SO_REUSEADDR
,
88 (char*)&one
, sizeof(one
));
89 status
= bind(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
92 status
= connect(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
93 } while (status
== -1 && errno
== EINTR
);
98 sock
->domain
= rp
->ai_family
;
99 sock
->type
= rp
->ai_socktype
;
100 sock
->protocol
= rp
->ai_protocol
;
106 clstat
= close(sock
->fd
);
108 clstat
= closesocket(sock
->fd
);
110 } while (clstat
== -1 && errno
== EINTR
);
113 freeaddrinfo(result
);
117 return nixio__perror_s(L
);
120 luaL_getmetatable(L
, NIXIO_META
);
121 lua_setmetatable(L
, -2);
127 * bind(host, port, [family=any], [type=any]) shortcut
129 static int nixio_bind(lua_State
*L
) {
130 return nixio__bind_connect(L
, 1);
134 * connect(host, port, [family=any], [type=any]) shortcut
136 static int nixio_connect(lua_State
*L
) {
137 return nixio__bind_connect(L
, 0);
141 * bind()/connect() helper
143 static int nixio_sock__bind_connect(lua_State
*L
, int do_bind
) {
144 nixio_sock
*sock
= nixio__checksock(L
);
147 if (sock
->domain
== AF_INET
|| sock
->domain
== AF_INET6
) {
148 const char *host
= NULL
;
149 if (!lua_isnoneornil(L
, 2)) {
150 host
= luaL_checklstring(L
, 2, NULL
);
152 const char *port
= luaL_checklstring(L
, 3, NULL
);
154 struct addrinfo hints
, *result
, *rp
;
156 memset(&hints
, 0, sizeof(hints
));
157 hints
.ai_family
= sock
->domain
;
158 hints
.ai_socktype
= sock
->type
;
159 hints
.ai_protocol
= sock
->protocol
;
162 hints
.ai_flags
|= AI_PASSIVE
;
165 int aistat
= getaddrinfo(host
, port
, &hints
, &result
);
168 lua_pushinteger(L
, aistat
);
169 lua_pushstring(L
, gai_strerror(aistat
));
173 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
175 status
= bind(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
178 status
= connect(sock
->fd
, rp
->ai_addr
, rp
->ai_addrlen
);
179 } while (status
== -1 && errno
== EINTR
);
183 if (!status
|| errno
== EINPROGRESS
) {
188 freeaddrinfo(result
);
190 } else if (sock
->domain
== AF_UNIX
) {
192 const char *path
= luaL_checklstring(L
, 2, &pathlen
);
194 struct sockaddr_un addr
;
195 addr
.sun_family
= AF_UNIX
;
196 luaL_argcheck(L
, pathlen
<= sizeof(addr
.sun_path
), 2, "out of range");
197 memcpy(addr
.sun_path
, path
, pathlen
);
198 socklen_t alen
= sizeof(sa_family_t
) + pathlen
;
201 status
= bind(sock
->fd
, (struct sockaddr
*)&addr
, alen
);
204 status
= connect(sock
->fd
, (struct sockaddr
*)&addr
, alen
);
205 } while (status
== -1 && errno
== EINTR
);
209 return luaL_error(L
, "not supported");
211 return nixio__pstatus_s(L
, !status
);
217 static int nixio_sock_bind(lua_State
*L
) {
218 return nixio_sock__bind_connect(L
, 1);
224 static int nixio_sock_connect(lua_State
*L
) {
225 return nixio_sock__bind_connect(L
, 0);
231 static int nixio_sock_listen(lua_State
*L
) {
232 int sockfd
= nixio__checksockfd(L
);
233 int backlog
= luaL_checkinteger(L
, 2);
234 return nixio__pstatus_s(L
, !listen(sockfd
, backlog
));
240 static int nixio_sock_accept(lua_State
*L
) {
241 nixio_sock
*sock
= nixio__checksock(L
);
242 struct sockaddr_storage saddr
;
244 socklen_t saddrlen
= sizeof(saddr
);
248 newfd
= accept(sock
->fd
, (struct sockaddr
*)&saddr
, &saddrlen
);
249 } while (newfd
== -1 && errno
== EINTR
);
251 return nixio__perror_s(L
);
254 /* create userdata */
255 nixio_sock
*clsock
= lua_newuserdata(L
, sizeof(nixio_sock
));
256 luaL_getmetatable(L
, NIXIO_META
);
257 lua_setmetatable(L
, -2);
259 memcpy(clsock
, sock
, sizeof(clsock
));
262 if (!nixio__addr_parse(&addr
, (struct sockaddr
*)&saddr
)) {
263 lua_pushstring(L
, addr
.host
);
264 lua_pushinteger(L
, addr
.port
);
272 static const luaL_reg R
[] = {
273 {"bind", nixio_bind
},
274 {"connect", nixio_connect
},
279 static const luaL_reg M
[] = {
280 {"bind", nixio_sock_bind
},
281 {"connect", nixio_sock_connect
},
282 {"listen", nixio_sock_listen
},
283 {"accept", nixio_sock_accept
},
287 void nixio_open_bind(lua_State
*L
) {
288 luaL_register(L
, NULL
, R
);
290 lua_pushvalue(L
, -2);
291 luaL_register(L
, NULL
, M
);