/* lsocket_sock_recvfrom * * reads data from a socket * * Arguments: * L Lua State * * Lua Stack: * 1 the lSocket userdata * 2 (optional) the length of the buffer to use for reading, defaults * to some internal value * * Lua Returns: * +1 a string containing the data read * +2 ip address if remote end * +3 port of remote end * or +1 false if nonblocking socket returned EAGAIN (no data available) * or +1 nil if the remote end has closed the socket * or +1 nil, +2 error message on error */ static int lsocket_sock_recvfrom(lua_State *L) { lSocket *sock = lsocket_checklSocket(L, 1); uint32_t howmuch = luaL_optnumber(L, 2, READER_BUFSIZ); if (lua_tonumber(L, 2) > UINT_MAX) return luaL_error(L, "bad argument #1 to 'recvfrom' (invalid number)"); char sabuf[sizeof(struct sockaddr_in6)]; struct sockaddr *sa = (struct sockaddr*) sabuf; socklen_t slen = sizeof(sabuf); char *buf = malloc(howmuch); int nrd = recvfrom(sock->sockfd, buf, howmuch, 0, sa, &slen); if (nrd < 0) { free(buf); if (errno == EAGAIN || errno == EWOULDBLOCK) lua_pushboolean(L, 0); else return lsocket_error(L, strerror(errno)); } else if (nrd == 0) lua_pushnil(L); /* not possible for udp, so should not get here */ else { lua_pushlstring(L, buf, nrd); free(buf); char ipbuf[TOSTRING_BUFSIZ]; const char *s = _addr2string(sa, ipbuf, TOSTRING_BUFSIZ); if (s) lua_pushstring(L, s); else return lsocket_error(L, strerror(errno)); /* should not happen */ lua_pushnumber(L, _portnumber(sa)); return 3; } return 1; }
/* lsocket_sock_accept * * accept a new connection on a socket * * Arguments: * L Lua State * * Lua Stack: * 1 the lSocket userdata * * Lua Returns: * +1 new socket, +2 client ip, +3 client port on success * or +1 false if nonblocking socket returned EAGAIN * or +1 nil, +2 error message on error */ static int lsocket_sock_accept(lua_State *L) { lSocket *sock = lsocket_checklSocket(L, 1); char buf[TOSTRING_BUFSIZ]; if (!_canacceptdata(sock->sockfd, 0)) { lua_pushboolean(L, 0); return 1; } char sabuf[sizeof(struct sockaddr_in6)]; struct sockaddr *sa = (struct sockaddr*) sabuf; socklen_t slen = sizeof(sabuf); int newfd = accept(sock->sockfd, sa, &slen); if (newfd < 0) return lsocket_error(L, strerror(errno)); lSocket *nsock = lsocket_pushlSocket(L); nsock->sockfd = newfd; if (_initsocket(nsock, sa->sa_family, sock->type, sock->mcast, sock->protocol, 0) == -1) return lsocket_error(L, strerror(errno)); lua_pushstring(L, _addr2string(sa, buf, TOSTRING_BUFSIZ)); lua_pushnumber(L, _portnumber(sa)); return 3; }
// deprecated: may hang up, use dns.resolve for cooperative dns query static int _resolve(lua_State *L) { const char* host = luaL_checkstring(L, 1); struct addrinfo *res = 0; int err, i; char buf[sizeof(struct in6_addr)]; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; err = getaddrinfo(host, NULL, &hints, &res); if(err != 0) { lua_pushnil(L); lua_pushinteger(L, err); return 2; } i = 1; lua_newtable(L); while(res) { // ignore all unsupported address if((res->ai_family == AF_INET || res->ai_family == AF_INET6) && res->ai_socktype == SOCK_STREAM) { lua_createtable(L, 0, 2); lua_pushinteger(L, res->ai_family); lua_setfield(L, -2, "family"); lua_pushstring(L, _addr2string(res->ai_addr, buf, sizeof(buf))); lua_setfield(L, -2, "addr"); lua_rawseti(L, -2, i++); } res = res->ai_next; } return 1; }
/* lsocket_getinterfaces * * enumerates all available interfaces * * Arguments: * L lua State * * Lua Stack: * - * * Lua Returns: * +1 a table with information on all available interfaces. For each * interface, a subtable is returned with the fields name, family, * address and mask */ static int lsocket_getinterfaces(lua_State *L) { struct ifaddrs *ifa; char buf[TOSTRING_BUFSIZ]; const char *s; int i = 1; if (getifaddrs(&ifa) < 0) return lsocket_error(L, strerror(errno)); lua_newtable(L); while (ifa) { lua_newtable(L); lua_pushliteral(L, "name"); lua_pushstring(L, ifa->ifa_name); lua_rawset(L, -3); s = _addr2string(ifa->ifa_addr, buf, TOSTRING_BUFSIZ); if (s) { lua_pushliteral(L, "family"); lua_pushstring(L, ifa->ifa_addr->sa_family == AF_INET ? LSOCKET_INET : LSOCKET_INET6); lua_rawset(L, -3); lua_pushliteral(L, "addr"); lua_pushstring(L, s); lua_rawset(L, -3); s = _addr2string(ifa->ifa_netmask, buf, TOSTRING_BUFSIZ); if (s) { lua_pushliteral(L, "mask"); lua_pushstring(L, s); lua_rawset(L, -3); } lua_rawseti(L, -2, i++); } else lua_pop(L, 1); ifa = ifa->ifa_next; } freeifaddrs(ifa); return 1; }
/* _push_sockname * * helper for lsocket_sock_info: create a table with fields port, family * and addr from the sockaddr passed as argument, and leave it on the * stack. Leave nil on error. * * Arguments: * L Lua State * sa pointer to sockaddr to get data from * * Lua Returns: * +1 table with info about address, or nil */ static void _push_sockname(lua_State *L, struct sockaddr *sa) { char buf[TOSTRING_BUFSIZ]; const char *s; lua_newtable(L); lua_pushliteral(L, "port"); lua_pushnumber(L, _portnumber(sa)); lua_rawset(L, -3); lua_pushliteral(L, "family"); lua_pushstring(L, sa->sa_family == AF_INET ? LSOCKET_INET : LSOCKET_INET6); lua_rawset(L, -3); lua_pushliteral(L, "addr"); s = _addr2string(sa, buf, TOSTRING_BUFSIZ); if (s) { lua_pushstring(L, s); lua_rawset(L, -3); } else { lua_pop(L, 1); } }
/* lsocket_resolve * * resolves a name to an address * * Arguments: * L lua State * * Lua Stack: * 1 name of host to resolve * * Lua Returns: * +1 a table of all addresses the argument resolves to. For each address, * a subtable with the fields family and addr is created. */ static int lsocket_resolve(lua_State *L) { const char *name = luaL_checkstring(L, 1); char buf[TOSTRING_BUFSIZ]; struct addrinfo hint, *info =0; memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_UNSPEC; if (_needsnolookup(name)) hint.ai_flags = AI_NUMERICHOST; int err = getaddrinfo(name, 0, &hint, &info); if (err != 0) { if (info) freeaddrinfo(info); return lsocket_error(L, gai_strerror(err)); } int i = 1; lua_newtable(L); while (info) { if (info->ai_family == AF_INET || info->ai_family == AF_INET6) { lua_newtable(L); lua_pushliteral(L, "family"); lua_pushstring(L, info->ai_family == AF_INET ? LSOCKET_INET : LSOCKET_INET6); lua_rawset(L, -3); lua_pushliteral(L, "addr"); lua_pushstring(L, _addr2string(info->ai_addr, buf, TOSTRING_BUFSIZ)); lua_rawset(L, -3); lua_rawseti(L, -2, i++); info = info->ai_next; } /* silently ignore unknown address families */ } freeaddrinfo(info); return 1; }