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 <netinet/in.h>
23 #include <netinet/tcp.h>
35 static int nixio_sock_setblocking(lua_State
*L
) {
36 int fd
= nixio__checkfd(L
, 1);
38 int set
= lua_toboolean(L
, 2);
39 int flags
= fcntl(fd
, F_GETFL
);
42 return nixio__perror(L
);
51 return nixio__pstatus(L
, !fcntl(fd
, F_SETFL
, flags
));
54 static int nixio__gso_int(lua_State
*L
, int fd
, int level
, int opt
, int set
) {
56 socklen_t optlen
= sizeof(value
);
58 if (!getsockopt(fd
, level
, opt
, &value
, &optlen
)) {
59 lua_pushinteger(L
, value
);
63 value
= luaL_checkinteger(L
, set
);
64 if (!setsockopt(fd
, level
, opt
, &value
, optlen
)) {
65 lua_pushboolean(L
, 1);
69 return nixio__perror(L
);
72 static int nixio__gso_ling(lua_State
*L
, int fd
, int level
, int opt
, int set
) {
74 socklen_t optlen
= sizeof(value
);
76 if (!getsockopt(fd
, level
, opt
, &value
, &optlen
)) {
77 lua_pushinteger(L
, value
.l_onoff
? value
.l_linger
: 0);
81 value
.l_linger
= luaL_checkinteger(L
, set
);
82 value
.l_onoff
= value
.l_linger
? 1 : 0;
83 if (!setsockopt(fd
, level
, opt
, &value
, optlen
)) {
84 lua_pushboolean(L
, 1);
88 return nixio__perror(L
);
91 static int nixio__gso_timev(lua_State
*L
, int fd
, int level
, int opt
, int set
) {
93 socklen_t optlen
= sizeof(value
);
95 if (!getsockopt(fd
, level
, opt
, &value
, &optlen
)) {
96 lua_pushinteger(L
, value
.tv_sec
);
97 lua_pushinteger(L
, value
.tv_usec
);
101 value
.tv_sec
= luaL_checkinteger(L
, set
);
102 value
.tv_usec
= luaL_optinteger(L
, set
+ 1, 0);
103 if (!setsockopt(fd
, level
, opt
, &value
, optlen
)) {
104 lua_pushboolean(L
, 1);
108 return nixio__perror(L
);
111 #ifdef SO_BINDTODEVICE
113 static int nixio__gso_b(lua_State
*L
, int fd
, int level
, int opt
, int set
) {
115 socklen_t optlen
= IFNAMSIZ
;
116 char ifname
[IFNAMSIZ
];
117 if (!getsockopt(fd
, level
, opt
, ifname
, &optlen
)) {
118 lua_pushlstring(L
, ifname
, optlen
);
123 const char *value
= luaL_checklstring(L
, set
, &valuelen
);
124 luaL_argcheck(L
, valuelen
<= IFNAMSIZ
, set
, "invalid interface name");
125 if (!setsockopt(fd
, level
, opt
, value
, valuelen
)) {
126 lua_pushboolean(L
, 1);
130 return nixio__perror(L
);
133 #endif /* SO_BINDTODEVICE */
136 * get/setsockopt() helper
138 static int nixio__getsetsockopt(lua_State
*L
, int set
) {
139 nixio_sock
*sock
= nixio__checksock(L
);
140 const char *level
= luaL_optlstring(L
, 2, "", NULL
);
141 const char *option
= luaL_optlstring(L
, 3, "", NULL
);
144 if (!strcmp(level
, "socket")) {
145 if (!strcmp(option
, "keepalive")) {
146 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_KEEPALIVE
, set
);
147 } else if (!strcmp(option
, "reuseaddr")) {
148 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_REUSEADDR
, set
);
149 } else if (!strcmp(option
, "rcvbuf")) {
150 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_RCVBUF
, set
);
151 } else if (!strcmp(option
, "sndbuf")) {
152 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_SNDBUF
, set
);
153 } else if (!strcmp(option
, "priority")) {
155 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_PRIORITY
, set
);
157 return nixio__pstatus(L
, !(errno
= ENOPROTOOPT
));
159 } else if (!strcmp(option
, "broadcast")) {
160 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_BROADCAST
, set
);
161 } else if (!strcmp(option
, "dontroute")) {
162 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_DONTROUTE
, set
);
163 } else if (!strcmp(option
, "error")) {
164 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_ERROR
, set
);
165 } else if (!strcmp(option
, "oobinline")) {
166 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_OOBINLINE
, set
);
167 } else if (!strcmp(option
, "linger")) {
168 return nixio__gso_ling(L
, sock
->fd
, SOL_SOCKET
, SO_LINGER
, set
);
169 } else if (!strcmp(option
, "sndtimeo")) {
170 return nixio__gso_timev(L
, sock
->fd
, SOL_SOCKET
, SO_SNDTIMEO
, set
);
171 } else if (!strcmp(option
, "rcvtimeo")) {
172 return nixio__gso_timev(L
, sock
->fd
, SOL_SOCKET
, SO_RCVTIMEO
, set
);
173 } else if (!strcmp(option
, "bindtodevice")) {
174 #ifdef SO_BINDTODEVICE
175 return nixio__gso_b(L
, sock
->fd
, SOL_SOCKET
, SO_BINDTODEVICE
, set
);
177 return nixio__pstatus(L
, !(errno
= ENOPROTOOPT
));
180 return luaL_argerror(L
, 3, "supported values: keepalive, reuseaddr,"
181 " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo,"
182 " dontroute, bindtodevice, error, oobinline"
185 } else if (!strcmp(level
, "tcp")) {
186 if (sock
->type
!= SOCK_STREAM
) {
187 return luaL_error(L
, "not a TCP socket");
189 if (!strcmp(option
, "cork")) {
191 return nixio__gso_int(L
, sock
->fd
, IPPROTO_TCP
, TCP_CORK
, set
);
193 return nixio__pstatus(L
, !(errno
= ENOPROTOOPT
));
195 } else if (!strcmp(option
, "nodelay")) {
196 return nixio__gso_int(L
, sock
->fd
, IPPROTO_TCP
, TCP_NODELAY
, set
);
198 return luaL_argerror(L
, 3, "supported values: cork, nodelay");
201 return luaL_argerror(L
, 2, "supported values: socket, tcp");
208 static int nixio_sock_getsockopt(lua_State
*L
) {
209 return nixio__getsetsockopt(L
, 0);
215 static int nixio_sock_setsockopt(lua_State
*L
) {
216 return nixio__getsetsockopt(L
, 1);
220 static const luaL_reg M
[] = {
221 {"setblocking", nixio_sock_setblocking
},
222 {"getsockopt", nixio_sock_getsockopt
},
223 {"setsockopt", nixio_sock_setsockopt
},
227 void nixio_open_sockopt(lua_State
*L
) {
228 lua_pushvalue(L
, -2);
229 luaL_register(L
, NULL
, M
);
232 luaL_getmetatable(L
, NIXIO_FILE_META
);
233 lua_pushcfunction(L
, nixio_sock_setblocking
);
234 lua_setfield(L
, -2, "setblocking");