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);
34 int set
= lua_toboolean(L
, 2);
35 int flags
= fcntl(fd
, F_GETFL
);
38 return nixio__perror(L
);
47 return nixio__pstatus(L
, !fcntl(fd
, F_SETFL
, flags
));
50 static int nixio__gso_int(lua_State
*L
, int fd
, int level
, int opt
, int set
) {
52 socklen_t optlen
= sizeof(value
);
54 if (!getsockopt(fd
, level
, opt
, &value
, &optlen
)) {
55 lua_pushinteger(L
, value
);
59 value
= luaL_checkinteger(L
, set
);
60 if (!setsockopt(fd
, level
, opt
, &value
, optlen
)) {
61 lua_pushboolean(L
, 1);
65 return nixio__perror(L
);
68 static int nixio__gso_ling(lua_State
*L
, int fd
, int level
, int opt
, int set
) {
70 socklen_t optlen
= sizeof(value
);
72 if (!getsockopt(fd
, level
, opt
, &value
, &optlen
)) {
73 lua_pushinteger(L
, value
.l_onoff
? value
.l_linger
: 0);
77 value
.l_linger
= luaL_checkinteger(L
, set
);
78 value
.l_onoff
= value
.l_linger
? 1 : 0;
79 if (!setsockopt(fd
, level
, opt
, &value
, optlen
)) {
80 lua_pushboolean(L
, 1);
84 return nixio__perror(L
);
87 static int nixio__gso_timev(lua_State
*L
, int fd
, int level
, int opt
, int set
) {
89 socklen_t optlen
= sizeof(value
);
91 if (!getsockopt(fd
, level
, opt
, &value
, &optlen
)) {
92 lua_pushinteger(L
, value
.tv_sec
);
93 lua_pushinteger(L
, value
.tv_usec
);
97 value
.tv_sec
= luaL_checkinteger(L
, set
);
98 value
.tv_usec
= luaL_optinteger(L
, set
+ 1, 0);
99 if (!setsockopt(fd
, level
, opt
, &value
, optlen
)) {
100 lua_pushboolean(L
, 1);
104 return nixio__perror(L
);
108 * get/setsockopt() helper
110 static int nixio__getsetsockopt(lua_State
*L
, int set
) {
111 nixio_sock
*sock
= nixio__checksock(L
);
112 const char *level
= luaL_optlstring(L
, 2, "", NULL
);
113 const char *option
= luaL_optlstring(L
, 3, "", NULL
);
116 if (!strcmp(level
, "socket")) {
117 if (!strcmp(option
, "keepalive")) {
118 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_KEEPALIVE
, set
);
119 } else if (!strcmp(option
, "reuseaddr")) {
120 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_REUSEADDR
, set
);
121 } else if (!strcmp(option
, "rcvbuf")) {
122 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_RCVBUF
, set
);
123 } else if (!strcmp(option
, "sndbuf")) {
124 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_SNDBUF
, set
);
125 } else if (!strcmp(option
, "priority")) {
126 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_PRIORITY
, set
);
127 } else if (!strcmp(option
, "broadcast")) {
128 return nixio__gso_int(L
, sock
->fd
, SOL_SOCKET
, SO_BROADCAST
, set
);
129 } else if (!strcmp(option
, "linger")) {
130 return nixio__gso_ling(L
, sock
->fd
, SOL_SOCKET
, SO_LINGER
, set
);
131 } else if (!strcmp(option
, "sndtimeo")) {
132 return nixio__gso_timev(L
, sock
->fd
, SOL_SOCKET
, SO_SNDTIMEO
, set
);
133 } else if (!strcmp(option
, "rcvtimeo")) {
134 return nixio__gso_timev(L
, sock
->fd
, SOL_SOCKET
, SO_RCVTIMEO
, set
);
136 return luaL_argerror(L
, 3, "supported values: keepalive, reuseaddr,"
137 " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo"
140 } else if (!strcmp(level
, "tcp")) {
141 if (sock
->type
!= SOCK_STREAM
) {
142 return luaL_error(L
, "not a TCP socket");
144 if (!strcmp(option
, "cork")) {
145 return nixio__gso_int(L
, sock
->fd
, SOL_TCP
, TCP_CORK
, set
);
146 } else if (!strcmp(option
, "nodelay")) {
147 return nixio__gso_int(L
, sock
->fd
, SOL_TCP
, TCP_NODELAY
, set
);
149 return luaL_argerror(L
, 3, "supported values: cork, nodelay");
152 return luaL_argerror(L
, 2, "supported values: socket, tcp");
159 static int nixio_sock_getsockopt(lua_State
*L
) {
160 return nixio__getsetsockopt(L
, 0);
166 static int nixio_sock_setsockopt(lua_State
*L
) {
167 return nixio__getsetsockopt(L
, 1);
171 static const luaL_reg M
[] = {
172 {"setblocking", nixio_sock_setblocking
},
173 {"getsockopt", nixio_sock_getsockopt
},
174 {"setsockopt", nixio_sock_setsockopt
},
178 void nixio_open_sockopt(lua_State
*L
) {
179 lua_pushvalue(L
, -2);
180 luaL_register(L
, NULL
, M
);
183 luaL_getmetatable(L
, NIXIO_FILE_META
);
184 lua_pushcfunction(L
, nixio_sock_setblocking
);
185 lua_setfield(L
, -2, "setblocking");