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/socket.h>
21 #include <netinet/in.h>
22 #include <netinet/tcp.h>
31 static int nixio_sock_setblocking(lua_State *L) {
32 int fd = nixio__checkfd(L, 1);
33 int set = lua_toboolean(L, 2);
34 int flags = fcntl(fd, F_GETFL);
37 return nixio__perror(L);
46 return nixio__pstatus(L, !fcntl(fd, F_SETFL, flags));
49 static int nixio__gso_int(lua_State *L, int fd, int level, int opt, int set) {
51 socklen_t optlen = sizeof(value);
53 if (!getsockopt(fd, level, opt, &value, &optlen)) {
54 lua_pushinteger(L, value);
58 value = luaL_checkinteger(L, set);
59 if (!setsockopt(fd, level, opt, &value, optlen)) {
60 lua_pushboolean(L, 1);
64 return nixio__perror(L);
67 static int nixio__gso_ling(lua_State *L, int fd, int level, int opt, int set) {
69 socklen_t optlen = sizeof(value);
71 if (!getsockopt(fd, level, opt, &value, &optlen)) {
72 lua_pushinteger(L, value.l_onoff ? value.l_linger : 0);
76 value.l_linger = luaL_checkinteger(L, set);
77 value.l_onoff = value.l_linger ? 1 : 0;
78 if (!setsockopt(fd, level, opt, &value, optlen)) {
79 lua_pushboolean(L, 1);
83 return nixio__perror(L);
86 static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) {
88 socklen_t optlen = sizeof(value);
90 if (!getsockopt(fd, level, opt, &value, &optlen)) {
91 lua_pushinteger(L, value.tv_sec);
92 lua_pushinteger(L, value.tv_usec);
96 value.tv_sec = luaL_checkinteger(L, set);
97 value.tv_usec = luaL_optinteger(L, set + 1, 0);
98 if (!setsockopt(fd, level, opt, &value, optlen)) {
99 lua_pushboolean(L, 1);
103 return nixio__perror(L);
107 * get/setsockopt() helper
109 static int nixio__getsetsockopt(lua_State *L, int set) {
110 nixio_sock *sock = nixio__checksock(L);
111 const char *level = luaL_optlstring(L, 2, "", NULL);
112 const char *option = luaL_optlstring(L, 3, "", NULL);
115 if (!strcmp(level, "socket")) {
116 if (!strcmp(option, "keepalive")) {
117 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_KEEPALIVE, set);
118 } else if (!strcmp(option, "reuseaddr")) {
119 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_REUSEADDR, set);
120 } else if (!strcmp(option, "rcvbuf")) {
121 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_RCVBUF, set);
122 } else if (!strcmp(option, "sndbuf")) {
123 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_SNDBUF, set);
124 } else if (!strcmp(option, "priority")) {
125 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_PRIORITY, set);
126 } else if (!strcmp(option, "broadcast")) {
127 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_BROADCAST, set);
128 } else if (!strcmp(option, "linger")) {
129 return nixio__gso_ling(L, sock->fd, SOL_SOCKET, SO_LINGER, set);
130 } else if (!strcmp(option, "sndtimeo")) {
131 return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_SNDTIMEO, set);
132 } else if (!strcmp(option, "rcvtimeo")) {
133 return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_RCVTIMEO, set);
135 return luaL_argerror(L, 3, "supported values: keepalive, reuseaddr,"
136 " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo"
139 } else if (!strcmp(level, "tcp")) {
140 if (sock->type != SOCK_STREAM) {
141 return luaL_error(L, "not a TCP socket");
143 if (!strcmp(option, "cork")) {
144 return nixio__gso_int(L, sock->fd, SOL_TCP, TCP_CORK, set);
145 } else if (!strcmp(option, "nodelay")) {
146 return nixio__gso_int(L, sock->fd, SOL_TCP, TCP_NODELAY, set);
148 return luaL_argerror(L, 3, "supported values: cork, nodelay");
151 return luaL_argerror(L, 2, "supported values: socket, tcp");
158 static int nixio_sock_getsockopt(lua_State *L) {
159 return nixio__getsetsockopt(L, 0);
165 static int nixio_sock_setsockopt(lua_State *L) {
166 return nixio__getsetsockopt(L, 1);
170 static const luaL_reg M[] = {
171 {"setblocking", nixio_sock_setblocking},
172 {"getsockopt", nixio_sock_getsockopt},
173 {"setsockopt", nixio_sock_setsockopt},
177 void nixio_open_sockopt(lua_State *L) {
178 lua_pushvalue(L, -2);
179 luaL_register(L, NULL, M);
182 luaL_getmetatable(L, NIXIO_FILE_META);
183 lua_pushcfunction(L, nixio_sock_setblocking);
184 lua_setfield(L, -2, "setblocking");