summaryrefslogtreecommitdiffhomepage
path: root/libs/nixio/src/sockopt.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/nixio/src/sockopt.c')
-rw-r--r--libs/nixio/src/sockopt.c192
1 files changed, 171 insertions, 21 deletions
diff --git a/libs/nixio/src/sockopt.c b/libs/nixio/src/sockopt.c
index 2d68d12ef..7e063e4a3 100644
--- a/libs/nixio/src/sockopt.c
+++ b/libs/nixio/src/sockopt.c
@@ -17,17 +17,25 @@
*/
#include "nixio.h"
+
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <net/if.h>
#include <sys/time.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
-#include "nixio.h"
+#ifndef IPV6_ADD_MEMBERSHIP
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#endif
+
+#ifndef IPV6_DROP_MEMBERSHIP
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#endif
+
+static int nixio_sock_fileno(lua_State *L) {
+ lua_pushinteger(L, nixio__checkfd(L, 1));
+ return 1;
+}
/**
* setblocking()
@@ -36,6 +44,9 @@ static int nixio_sock_setblocking(lua_State *L) {
int fd = nixio__checkfd(L, 1);
luaL_checkany(L, 2);
int set = lua_toboolean(L, 2);
+
+#ifndef __WINNT__
+
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
@@ -49,50 +60,64 @@ static int nixio_sock_setblocking(lua_State *L) {
}
return nixio__pstatus(L, !fcntl(fd, F_SETFL, flags));
+
+#else /* __WINNT__ */
+
+ lua_getmetatable(L, 1);
+ luaL_getmetatable(L, NIXIO_META);
+ if (lua_equal(L, -1, -2)) { /* Socket */
+ unsigned long val = !set;
+ return nixio__pstatus_s(L, !ioctlsocket(fd, FIONBIO, &val));
+ } else { /* File */
+ WSASetLastError(WSAENOTSOCK);
+ return nixio__perror_s(L);
+ }
+
+#endif /* __WINNT__ */
}
static int nixio__gso_int(lua_State *L, int fd, int level, int opt, int set) {
int value;
socklen_t optlen = sizeof(value);
if (!set) {
- if (!getsockopt(fd, level, opt, &value, &optlen)) {
+ if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
lua_pushinteger(L, value);
return 1;
}
} else {
value = luaL_checkinteger(L, set);
- if (!setsockopt(fd, level, opt, &value, optlen)) {
+ if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
lua_pushboolean(L, 1);
return 1;
}
}
- return nixio__perror(L);
+ return nixio__perror_s(L);
}
static int nixio__gso_ling(lua_State *L, int fd, int level, int opt, int set) {
struct linger value;
socklen_t optlen = sizeof(value);
if (!set) {
- if (!getsockopt(fd, level, opt, &value, &optlen)) {
+ if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
lua_pushinteger(L, value.l_onoff ? value.l_linger : 0);
return 1;
}
} else {
value.l_linger = luaL_checkinteger(L, set);
value.l_onoff = value.l_linger ? 1 : 0;
- if (!setsockopt(fd, level, opt, &value, optlen)) {
+ if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
lua_pushboolean(L, 1);
return 1;
}
}
- return nixio__perror(L);
+ return nixio__perror_s(L);
}
static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) {
struct timeval value;
socklen_t optlen = sizeof(value);
if (!set) {
- if (!getsockopt(fd, level, opt, &value, &optlen)) {
+ if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
lua_pushinteger(L, value.tv_sec);
lua_pushinteger(L, value.tv_usec);
return 2;
@@ -100,12 +125,12 @@ static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) {
} else {
value.tv_sec = luaL_checkinteger(L, set);
value.tv_usec = luaL_optinteger(L, set + 1, 0);
- if (!setsockopt(fd, level, opt, &value, optlen)) {
+ if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
lua_pushboolean(L, 1);
return 1;
}
}
- return nixio__perror(L);
+ return nixio__perror_s(L);
}
#ifdef SO_BINDTODEVICE
@@ -114,7 +139,7 @@ static int nixio__gso_b(lua_State *L, int fd, int level, int opt, int set) {
if (!set) {
socklen_t optlen = IFNAMSIZ;
char ifname[IFNAMSIZ];
- if (!getsockopt(fd, level, opt, ifname, &optlen)) {
+ if (!getsockopt(fd, level, opt, (char *)ifname, &optlen)) {
lua_pushlstring(L, ifname, optlen);
return 1;
}
@@ -122,16 +147,76 @@ static int nixio__gso_b(lua_State *L, int fd, int level, int opt, int set) {
size_t valuelen;
const char *value = luaL_checklstring(L, set, &valuelen);
luaL_argcheck(L, valuelen <= IFNAMSIZ, set, "invalid interface name");
- if (!setsockopt(fd, level, opt, value, valuelen)) {
+ if (!setsockopt(fd, level, opt, (char *)value, valuelen)) {
lua_pushboolean(L, 1);
return 1;
}
}
- return nixio__perror(L);
+ return nixio__perror_s(L);
}
#endif /* SO_BINDTODEVICE */
+static int nixio__gso_mreq4(lua_State *L, int fd, int level, int opt, int set) {
+ struct ip_mreq value;
+ socklen_t optlen = sizeof(value);
+ if (!set) {
+ char buf[INET_ADDRSTRLEN];
+ if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) {
+ if (!inet_ntop(AF_INET, &value.imr_multiaddr, buf, sizeof(buf))) {
+ return nixio__perror_s(L);
+ }
+ lua_pushstring(L, buf);
+ if (!inet_ntop(AF_INET, &value.imr_interface, buf, sizeof(buf))) {
+ return nixio__perror_s(L);
+ }
+ lua_pushstring(L, buf);
+ return 2;
+ }
+ } else {
+ const char *maddr = luaL_checkstring(L, set);
+ const char *iface = luaL_optstring(L, set + 1, "0.0.0.0");
+ if (inet_pton(AF_INET, maddr, &value.imr_multiaddr) < 1) {
+ return nixio__perror_s(L);
+ }
+ if (inet_pton(AF_INET, iface, &value.imr_interface) < 1) {
+ return nixio__perror_s(L);
+ }
+ if (!setsockopt(fd, level, opt, (char *)&value, optlen)) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ }
+ return nixio__perror_s(L);
+}
+
+static int nixio__gso_mreq6(lua_State *L, int fd, int level, int opt, int set) {
+ struct ipv6_mreq val;
+ socklen_t optlen = sizeof(val);
+ if (!set) {
+ char buf[INET_ADDRSTRLEN];
+ if (!getsockopt(fd, level, opt, (char *)&val, &optlen)) {
+ if (!inet_ntop(AF_INET6, &val.ipv6mr_multiaddr, buf, sizeof(buf))) {
+ return nixio__perror_s(L);
+ }
+ lua_pushstring(L, buf);
+ lua_pushnumber(L, val.ipv6mr_interface);
+ return 2;
+ }
+ } else {
+ const char *maddr = luaL_checkstring(L, set);
+ if (inet_pton(AF_INET6, maddr, &val.ipv6mr_multiaddr) < 1) {
+ return nixio__perror_s(L);
+ }
+ val.ipv6mr_interface = luaL_optlong(L, set + 1, 0);
+ if (!setsockopt(fd, level, opt, (char *)&val, optlen)) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ }
+ return nixio__perror_s(L);
+}
+
/**
* get/setsockopt() helper
*/
@@ -183,9 +268,6 @@ static int nixio__getsetsockopt(lua_State *L, int set) {
);
}
} else if (!strcmp(level, "tcp")) {
- if (sock->type != SOCK_STREAM) {
- return luaL_error(L, "not a TCP socket");
- }
if (!strcmp(option, "cork")) {
#ifdef TCP_CORK
return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_CORK, set);
@@ -197,8 +279,71 @@ static int nixio__getsetsockopt(lua_State *L, int set) {
} else {
return luaL_argerror(L, 3, "supported values: cork, nodelay");
}
+ } else if (!strcmp(level, "ip")) {
+ if (!strcmp(option, "mtu")) {
+#ifdef IP_MTU
+ return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MTU, set);
+#else
+ return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
+ } else if (!strcmp(option, "hdrincl")) {
+ return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_HDRINCL,
+ set);
+ } else if (!strcmp(option, "multicast_loop")) {
+ return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ set);
+ } else if (!strcmp(option, "multicast_ttl")) {
+ return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_TTL,
+ set);
+ } else if (!strcmp(option, "multicast_if")) {
+ return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_MULTICAST_IF,
+ set);
+ } else if (!strcmp(option, "add_membership")) {
+ return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ set);
+ } else if (!strcmp(option, "drop_membership")) {
+ return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ set);
+ } else {
+ return luaL_argerror(L, 3,
+ "supported values: hdrincl, mtu, multicast_loop, "
+ "multicast_ttl, multicast_if, add_membership, drop_membership");
+ }
+ } else if (!strcmp(level, "ipv6")) {
+ if (!strcmp(option, "mtu")) {
+#ifdef IPV6_MTU
+ return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_MTU, set);
+#else
+ return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
+ } else if (!strcmp(option, "v6only")) {
+#ifdef IPV6_V6ONLY
+ return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, set);
+#else
+ return nixio__pstatus(L, !(errno = ENOPROTOOPT));
+#endif
+ } else if (!strcmp(option, "multicast_loop")) {
+ return nixio__gso_int(L, sock->fd, IPPROTO_IPV6,
+ IPV6_MULTICAST_LOOP, set);
+ } else if (!strcmp(option, "multicast_hops")) {
+ return nixio__gso_int(L, sock->fd, IPPROTO_IPV6,
+ IPV6_MULTICAST_HOPS, set);
+ } else if (!strcmp(option, "multicast_if")) {
+ return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6,
+ IPV6_MULTICAST_IF, set);
+ } else if (!strcmp(option, "add_membership")) {
+ return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6,
+ IPV6_ADD_MEMBERSHIP, set);
+ } else if (!strcmp(option, "drop_membership")) {
+ return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6,
+ IPV6_DROP_MEMBERSHIP, set);
+ } else {
+ return luaL_argerror(L, 3,
+ "supported values: v6only, mtu, multicast_loop, multicast_hops,"
+ " multicast_if, add_membership, drop_membership");
+ }
} else {
- return luaL_argerror(L, 2, "supported values: socket, tcp");
+ return luaL_argerror(L, 2, "supported values: socket, tcp, ip, ipv6");
}
}
@@ -221,6 +366,9 @@ static const luaL_reg M[] = {
{"setblocking", nixio_sock_setblocking},
{"getsockopt", nixio_sock_getsockopt},
{"setsockopt", nixio_sock_setsockopt},
+ {"getopt", nixio_sock_getsockopt},
+ {"setopt", nixio_sock_setsockopt},
+ {"fileno", nixio_sock_fileno},
{NULL, NULL}
};
@@ -232,5 +380,7 @@ void nixio_open_sockopt(lua_State *L) {
luaL_getmetatable(L, NIXIO_FILE_META);
lua_pushcfunction(L, nixio_sock_setblocking);
lua_setfield(L, -2, "setblocking");
+ lua_pushcfunction(L, nixio_sock_fileno);
+ lua_setfield(L, -2, "fileno");
lua_pop(L, 1);
}