123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- /*=========================================================================*\
- * Unix domain socket dgram submodule
- * LuaSocket toolkit
- \*=========================================================================*/
- #include "luasocket.h"
- #include "auxiliar.h"
- #include "socket.h"
- #include "options.h"
- #include "unix.h"
- #include <string.h>
- #include <stdlib.h>
- #ifdef _WIN32
- #include <afunix.h>
- #else
- #include <sys/un.h>
- #endif
- #define UNIXDGRAM_DATAGRAMSIZE 8192
- /* provide a SUN_LEN macro if sys/un.h doesn't (e.g. Android) */
- #ifndef SUN_LEN
- #define SUN_LEN(ptr) \
- ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
- + strlen ((ptr)->sun_path))
- #endif
- /*=========================================================================*\
- * Internal function prototypes
- \*=========================================================================*/
- static int global_create(lua_State *L);
- static int meth_connect(lua_State *L);
- static int meth_bind(lua_State *L);
- static int meth_send(lua_State *L);
- static int meth_receive(lua_State *L);
- static int meth_close(lua_State *L);
- static int meth_setoption(lua_State *L);
- static int meth_settimeout(lua_State *L);
- static int meth_gettimeout(lua_State *L);
- static int meth_getfd(lua_State *L);
- static int meth_setfd(lua_State *L);
- static int meth_dirty(lua_State *L);
- static int meth_receivefrom(lua_State *L);
- static int meth_sendto(lua_State *L);
- static int meth_getsockname(lua_State *L);
- static const char *unixdgram_tryconnect(p_unix un, const char *path);
- static const char *unixdgram_trybind(p_unix un, const char *path);
- /* unixdgram object methods */
- static luaL_Reg unixdgram_methods[] = {
- {"__gc", meth_close},
- {"__tostring", auxiliar_tostring},
- {"bind", meth_bind},
- {"close", meth_close},
- {"connect", meth_connect},
- {"dirty", meth_dirty},
- {"getfd", meth_getfd},
- {"send", meth_send},
- {"sendto", meth_sendto},
- {"receive", meth_receive},
- {"receivefrom", meth_receivefrom},
- {"setfd", meth_setfd},
- {"setoption", meth_setoption},
- {"setpeername", meth_connect},
- {"setsockname", meth_bind},
- {"getsockname", meth_getsockname},
- {"settimeout", meth_settimeout},
- {"gettimeout", meth_gettimeout},
- {NULL, NULL}
- };
- /* socket option handlers */
- static t_opt optset[] = {
- {"reuseaddr", opt_set_reuseaddr},
- {NULL, NULL}
- };
- /* functions in library namespace */
- static luaL_Reg func[] = {
- {"dgram", global_create},
- {NULL, NULL}
- };
- /*-------------------------------------------------------------------------*\
- * Initializes module
- \*-------------------------------------------------------------------------*/
- int unixdgram_open(lua_State *L)
- {
- /* create classes */
- auxiliar_newclass(L, "unixdgram{connected}", unixdgram_methods);
- auxiliar_newclass(L, "unixdgram{unconnected}", unixdgram_methods);
- /* create class groups */
- auxiliar_add2group(L, "unixdgram{connected}", "unixdgram{any}");
- auxiliar_add2group(L, "unixdgram{unconnected}", "unixdgram{any}");
- auxiliar_add2group(L, "unixdgram{connected}", "select{able}");
- auxiliar_add2group(L, "unixdgram{unconnected}", "select{able}");
- luaL_setfuncs(L, func, 0);
- return 0;
- }
- /*=========================================================================*\
- * Lua methods
- \*=========================================================================*/
- static const char *unixdgram_strerror(int err)
- {
- /* a 'closed' error on an unconnected means the target address was not
- * accepted by the transport layer */
- if (err == IO_CLOSED) return "refused";
- else return socket_strerror(err);
- }
- static int meth_send(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{connected}", 1);
- p_timeout tm = &un->tm;
- size_t count, sent = 0;
- int err;
- const char *data = luaL_checklstring(L, 2, &count);
- timeout_markstart(tm);
- err = socket_send(&un->sock, data, count, &sent, tm);
- if (err != IO_DONE) {
- lua_pushnil(L);
- lua_pushstring(L, unixdgram_strerror(err));
- return 2;
- }
- lua_pushnumber(L, (lua_Number) sent);
- return 1;
- }
- /*-------------------------------------------------------------------------*\
- * Send data through unconnected unixdgram socket
- \*-------------------------------------------------------------------------*/
- static int meth_sendto(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
- size_t count, sent = 0;
- const char *data = luaL_checklstring(L, 2, &count);
- const char *path = luaL_checkstring(L, 3);
- p_timeout tm = &un->tm;
- int err;
- struct sockaddr_un remote;
- size_t len = strlen(path);
- if (len >= sizeof(remote.sun_path)) {
- lua_pushnil(L);
- lua_pushstring(L, "path too long");
- return 2;
- }
- memset(&remote, 0, sizeof(remote));
- strcpy(remote.sun_path, path);
- remote.sun_family = AF_UNIX;
- timeout_markstart(tm);
- #ifdef UNIX_HAS_SUN_LEN
- remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
- + len + 1;
- err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote, remote.sun_len, tm);
- #else
- err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote,
- sizeof(remote.sun_family) + len, tm);
- #endif
- if (err != IO_DONE) {
- lua_pushnil(L);
- lua_pushstring(L, unixdgram_strerror(err));
- return 2;
- }
- lua_pushnumber(L, (lua_Number) sent);
- return 1;
- }
- static int meth_receive(lua_State *L) {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- char buf[UNIXDGRAM_DATAGRAMSIZE];
- size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
- char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
- int err;
- p_timeout tm = &un->tm;
- timeout_markstart(tm);
- if (!dgram) {
- lua_pushnil(L);
- lua_pushliteral(L, "out of memory");
- return 2;
- }
- err = socket_recv(&un->sock, dgram, wanted, &got, tm);
- /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
- if (err != IO_DONE && err != IO_CLOSED) {
- lua_pushnil(L);
- lua_pushstring(L, unixdgram_strerror(err));
- if (wanted > sizeof(buf)) free(dgram);
- return 2;
- }
- lua_pushlstring(L, dgram, got);
- if (wanted > sizeof(buf)) free(dgram);
- return 1;
- }
- /*-------------------------------------------------------------------------*\
- * Receives data and sender from a DGRAM socket
- \*-------------------------------------------------------------------------*/
- static int meth_receivefrom(lua_State *L) {
- p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
- char buf[UNIXDGRAM_DATAGRAMSIZE];
- size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
- char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
- struct sockaddr_un addr;
- socklen_t addr_len = sizeof(addr);
- int err;
- p_timeout tm = &un->tm;
- timeout_markstart(tm);
- if (!dgram) {
- lua_pushnil(L);
- lua_pushliteral(L, "out of memory");
- return 2;
- }
- addr.sun_path[0] = '\0';
- err = socket_recvfrom(&un->sock, dgram, wanted, &got, (SA *) &addr,
- &addr_len, tm);
- /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
- if (err != IO_DONE && err != IO_CLOSED) {
- lua_pushnil(L);
- lua_pushstring(L, unixdgram_strerror(err));
- if (wanted > sizeof(buf)) free(dgram);
- return 2;
- }
- lua_pushlstring(L, dgram, got);
- /* the path may be empty, when client send without bind */
- lua_pushstring(L, addr.sun_path);
- if (wanted > sizeof(buf)) free(dgram);
- return 2;
- }
- /*-------------------------------------------------------------------------*\
- * Just call option handler
- \*-------------------------------------------------------------------------*/
- static int meth_setoption(lua_State *L) {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- return opt_meth_setoption(L, optset, &un->sock);
- }
- /*-------------------------------------------------------------------------*\
- * Select support methods
- \*-------------------------------------------------------------------------*/
- static int meth_getfd(lua_State *L) {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- lua_pushnumber(L, (int) un->sock);
- return 1;
- }
- /* this is very dangerous, but can be handy for those that are brave enough */
- static int meth_setfd(lua_State *L) {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- un->sock = (t_socket) luaL_checknumber(L, 2);
- return 0;
- }
- static int meth_dirty(lua_State *L) {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- (void) un;
- lua_pushboolean(L, 0);
- return 1;
- }
- /*-------------------------------------------------------------------------*\
- * Binds an object to an address
- \*-------------------------------------------------------------------------*/
- static const char *unixdgram_trybind(p_unix un, const char *path) {
- struct sockaddr_un local;
- size_t len = strlen(path);
- if (len >= sizeof(local.sun_path)) return "path too long";
- memset(&local, 0, sizeof(local));
- strcpy(local.sun_path, path);
- local.sun_family = AF_UNIX;
- size_t addrlen = SUN_LEN(&local);
- #ifdef UNIX_HAS_SUN_LEN
- local.sun_len = addrlen + 1;
- #endif
- int err = socket_bind(&un->sock, (SA *) &local, addrlen);
- if (err != IO_DONE) socket_destroy(&un->sock);
- return socket_strerror(err);
- }
- static int meth_bind(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
- const char *path = luaL_checkstring(L, 2);
- const char *err = unixdgram_trybind(un, path);
- if (err) {
- lua_pushnil(L);
- lua_pushstring(L, err);
- return 2;
- }
- lua_pushnumber(L, 1);
- return 1;
- }
- static int meth_getsockname(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- struct sockaddr_un peer = {0};
- socklen_t peer_len = sizeof(peer);
- if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
- lua_pushnil(L);
- lua_pushstring(L, socket_strerror(errno));
- return 2;
- }
- lua_pushstring(L, peer.sun_path);
- return 1;
- }
- /*-------------------------------------------------------------------------*\
- * Turns a master unixdgram object into a client object.
- \*-------------------------------------------------------------------------*/
- static const char *unixdgram_tryconnect(p_unix un, const char *path)
- {
- struct sockaddr_un remote;
- size_t len = strlen(path);
- if (len >= sizeof(remote.sun_path)) return "path too long";
- memset(&remote, 0, sizeof(remote));
- strcpy(remote.sun_path, path);
- remote.sun_family = AF_UNIX;
- timeout_markstart(&un->tm);
- size_t addrlen = SUN_LEN(&remote);
- #ifdef UNIX_HAS_SUN_LEN
- remote.sun_len = addrlen + 1;
- #endif
- int err = socket_connect(&un->sock, (SA *) &remote, addrlen, &un->tm);
- if (err != IO_DONE) socket_destroy(&un->sock);
- return socket_strerror(err);
- }
- static int meth_connect(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- const char *path = luaL_checkstring(L, 2);
- const char *err = unixdgram_tryconnect(un, path);
- if (err) {
- lua_pushnil(L);
- lua_pushstring(L, err);
- return 2;
- }
- /* turn unconnected object into a connected object */
- auxiliar_setclass(L, "unixdgram{connected}", 1);
- lua_pushnumber(L, 1);
- return 1;
- }
- /*-------------------------------------------------------------------------*\
- * Closes socket used by object
- \*-------------------------------------------------------------------------*/
- static int meth_close(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- socket_destroy(&un->sock);
- lua_pushnumber(L, 1);
- return 1;
- }
- /*-------------------------------------------------------------------------*\
- * Just call tm methods
- \*-------------------------------------------------------------------------*/
- static int meth_settimeout(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- return timeout_meth_settimeout(L, &un->tm);
- }
- static int meth_gettimeout(lua_State *L)
- {
- p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
- return timeout_meth_gettimeout(L, &un->tm);
- }
- /*=========================================================================*\
- * Library functions
- \*=========================================================================*/
- /*-------------------------------------------------------------------------*\
- * Creates a master unixdgram object
- \*-------------------------------------------------------------------------*/
- static int global_create(lua_State *L)
- {
- t_socket sock;
- int err = socket_create(&sock, AF_UNIX, SOCK_DGRAM, 0);
- /* try to allocate a system socket */
- if (err == IO_DONE) {
- /* allocate unixdgram object */
- p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
- /* set its type as master object */
- auxiliar_setclass(L, "unixdgram{unconnected}", -1);
- /* initialize remaining structure fields */
- socket_setnonblocking(&sock);
- un->sock = sock;
- io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
- (p_error) socket_ioerror, &un->sock);
- timeout_init(&un->tm, -1, -1);
- buffer_init(&un->buf, &un->io, &un->tm);
- return 1;
- } else {
- lua_pushnil(L);
- lua_pushstring(L, socket_strerror(err));
- return 2;
- }
- }
|