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>
33 static int nixio_sock_setblocking(lua_State *L) {
34 int fd = nixio__checkfd(L, 1);
36 int set = lua_toboolean(L, 2);
37 int flags = fcntl(fd, F_GETFL);
40 return nixio__perror(L);
49 return nixio__pstatus(L, !fcntl(fd, F_SETFL, flags));
52 static int nixio__gso_int(lua_State *L, int fd, int level, int opt, int set) {
54 socklen_t optlen = sizeof(value);
56 if (!getsockopt(fd, level, opt, &value, &optlen)) {
57 lua_pushinteger(L, value);
61 value = luaL_checkinteger(L, set);
62 if (!setsockopt(fd, level, opt, &value, optlen)) {
63 lua_pushboolean(L, 1);
67 return nixio__perror(L);
70 static int nixio__gso_ling(lua_State *L, int fd, int level, int opt, int set) {
72 socklen_t optlen = sizeof(value);
74 if (!getsockopt(fd, level, opt, &value, &optlen)) {
75 lua_pushinteger(L, value.l_onoff ? value.l_linger : 0);
79 value.l_linger = luaL_checkinteger(L, set);
80 value.l_onoff = value.l_linger ? 1 : 0;
81 if (!setsockopt(fd, level, opt, &value, optlen)) {
82 lua_pushboolean(L, 1);
86 return nixio__perror(L);
89 static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) {
91 socklen_t optlen = sizeof(value);
93 if (!getsockopt(fd, level, opt, &value, &optlen)) {
94 lua_pushinteger(L, value.tv_sec);
95 lua_pushinteger(L, value.tv_usec);
99 value.tv_sec = luaL_checkinteger(L, set);
100 value.tv_usec = luaL_optinteger(L, set + 1, 0);
101 if (!setsockopt(fd, level, opt, &value, optlen)) {
102 lua_pushboolean(L, 1);
106 return nixio__perror(L);
110 * get/setsockopt() helper
112 static int nixio__getsetsockopt(lua_State *L, int set) {
113 nixio_sock *sock = nixio__checksock(L);
114 const char *level = luaL_optlstring(L, 2, "", NULL);
115 const char *option = luaL_optlstring(L, 3, "", NULL);
118 if (!strcmp(level, "socket")) {
119 if (!strcmp(option, "keepalive")) {
120 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_KEEPALIVE, set);
121 } else if (!strcmp(option, "reuseaddr")) {
122 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_REUSEADDR, set);
123 } else if (!strcmp(option, "rcvbuf")) {
124 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_RCVBUF, set);
125 } else if (!strcmp(option, "sndbuf")) {
126 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_SNDBUF, set);
127 } else if (!strcmp(option, "priority")) {
129 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_PRIORITY, set);
131 return nixio__pstatus(L, !(errno = ENOPROTOOPT));
133 } else if (!strcmp(option, "broadcast")) {
134 return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_BROADCAST, set);
135 } else if (!strcmp(option, "linger")) {
136 return nixio__gso_ling(L, sock->fd, SOL_SOCKET, SO_LINGER, set);
137 } else if (!strcmp(option, "sndtimeo")) {
138 return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_SNDTIMEO, set);
139 } else if (!strcmp(option, "rcvtimeo")) {
140 return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_RCVTIMEO, set);
142 return luaL_argerror(L, 3, "supported values: keepalive, reuseaddr,"
143 " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo"
146 } else if (!strcmp(level, "tcp")) {
147 if (sock->type != SOCK_STREAM) {
148 return luaL_error(L, "not a TCP socket");
150 if (!strcmp(option, "cork")) {
151 return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_CORK, set);
152 } else if (!strcmp(option, "nodelay")) {
153 return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_NODELAY, set);
155 return luaL_argerror(L, 3, "supported values: cork, nodelay");
158 return luaL_argerror(L, 2, "supported values: socket, tcp");
165 static int nixio_sock_getsockopt(lua_State *L) {
166 return nixio__getsetsockopt(L, 0);
172 static int nixio_sock_setsockopt(lua_State *L) {
173 return nixio__getsetsockopt(L, 1);
177 static const luaL_reg M[] = {
178 {"setblocking", nixio_sock_setblocking},
179 {"getsockopt", nixio_sock_getsockopt},
180 {"setsockopt", nixio_sock_setsockopt},
184 void nixio_open_sockopt(lua_State *L) {
185 lua_pushvalue(L, -2);
186 luaL_register(L, NULL, M);
189 luaL_getmetatable(L, NIXIO_FILE_META);
190 lua_pushcfunction(L, nixio_sock_setblocking);
191 lua_setfield(L, -2, "setblocking");