mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-25 20:18:21 +01:00
Changed buffer-per-socket to buffer-per-operation.
This is a difficult tradeoff to measure. I think large datagrams won't be used very frequently. So it is better to not lock a large buffer to each socket object and instead allocate and deallocate for each operation receiving a datagram larger than UDP_DATAGRAMSIZE.
This commit is contained in:
parent
fd729b32a8
commit
be67f63f4e
@ -147,6 +147,7 @@ Support, Manual">
|
|||||||
<a href="socket.html#connect">connect</a>,
|
<a href="socket.html#connect">connect</a>,
|
||||||
<a href="socket.html#connect">connect4</a>,
|
<a href="socket.html#connect">connect4</a>,
|
||||||
<a href="socket.html#connect">connect6</a>,
|
<a href="socket.html#connect">connect6</a>,
|
||||||
|
<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
|
||||||
<a href="socket.html#debug">_DEBUG</a>,
|
<a href="socket.html#debug">_DEBUG</a>,
|
||||||
<a href="dns.html#dns">dns</a>,
|
<a href="dns.html#dns">dns</a>,
|
||||||
<a href="socket.html#gettime">gettime</a>,
|
<a href="socket.html#gettime">gettime</a>,
|
||||||
@ -158,6 +159,7 @@ Support, Manual">
|
|||||||
<a href="socket.html#skip">skip</a>,
|
<a href="socket.html#skip">skip</a>,
|
||||||
<a href="socket.html#sleep">sleep</a>,
|
<a href="socket.html#sleep">sleep</a>,
|
||||||
<a href="socket.html#setsize">_SETSIZE</a>,
|
<a href="socket.html#setsize">_SETSIZE</a>,
|
||||||
|
<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
|
||||||
<a href="socket.html#source">source</a>,
|
<a href="socket.html#source">source</a>,
|
||||||
<a href="tcp.html#socket.tcp">tcp</a>,
|
<a href="tcp.html#socket.tcp">tcp</a>,
|
||||||
<a href="tcp.html#socket.tcp4">tcp4</a>,
|
<a href="tcp.html#socket.tcp4">tcp4</a>,
|
||||||
|
@ -99,6 +99,19 @@ This constant is set to <tt><b>true</b></tt> if the library was compiled
|
|||||||
with debug support.
|
with debug support.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id=debug>
|
||||||
|
socket.<b>_DATAGRAMSIZE</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Default datagram size used by calls to
|
||||||
|
<a href="udp.html#receive"<tt>receive</tt></a> and
|
||||||
|
<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
|
||||||
|
(Unless changed in compile time, the value is 8192.)
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=gettime>
|
<p class=name id=gettime>
|
||||||
@ -393,6 +406,16 @@ The maximum number of sockets that the <a
|
|||||||
href=#select><tt>select</tt></a> function can handle.
|
href=#select><tt>select</tt></a> function can handle.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id=socketinvalid>
|
||||||
|
socket.<b>_SOCKETINVALID</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
The OS value for an invalid socket.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=try>
|
<p class=name id=try>
|
||||||
|
33
doc/udp.html
33
doc/udp.html
@ -42,7 +42,7 @@
|
|||||||
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="socket.udp">
|
<p class="name" id="socket.udp">
|
||||||
socket.<b>udp(</b>[buffersize]<b>)</b>
|
socket.<b>udp()</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="description">
|
<p class="description">
|
||||||
@ -62,13 +62,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
|
|||||||
is used to connect the object.
|
is used to connect the object.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="parameters">
|
|
||||||
The optional <tt>buffersize</tt> parameter
|
|
||||||
specifies the size of the largest datagram that will
|
|
||||||
ever be received by the UDP object. The default value is
|
|
||||||
8192.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="return">
|
<p class="return">
|
||||||
In case of success, a new unconnected UDP object
|
In case of success, a new unconnected UDP object
|
||||||
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
||||||
@ -92,7 +85,7 @@ href=#setoption><tt>setoption</tt></a> will fail.
|
|||||||
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="socket.udp">
|
<p class="name" id="socket.udp">
|
||||||
socket.<b>udp4(</b>[buffersize]<b>)</b>
|
socket.<b>udp4()</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="description">
|
<p class="description">
|
||||||
@ -112,13 +105,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
|
|||||||
is used to connect the object.
|
is used to connect the object.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="parameters">
|
|
||||||
The optional <tt>buffersize</tt> parameter
|
|
||||||
specifies the size of the largest datagram that will
|
|
||||||
ever be received by the UDP object. The default value is
|
|
||||||
8192.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="return">
|
<p class="return">
|
||||||
In case of success, a new unconnected UDP object
|
In case of success, a new unconnected UDP object
|
||||||
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
||||||
@ -128,7 +114,7 @@ an error message.
|
|||||||
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="socket.udp6">
|
<p class="name" id="socket.udp6">
|
||||||
socket.<b>udp6(</b>[buffersize]<b>)</b>
|
socket.<b>udp6()</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="description">
|
<p class="description">
|
||||||
@ -148,13 +134,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
|
|||||||
is used to connect the object.
|
is used to connect the object.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="parameters">
|
|
||||||
The optional <tt>buffersize</tt> parameter
|
|
||||||
specifies the size of the largest datagram that will
|
|
||||||
ever be received by the UDP object. The default value is
|
|
||||||
8192.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="return">
|
<p class="return">
|
||||||
In case of success, a new unconnected UDP object
|
In case of success, a new unconnected UDP object
|
||||||
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
||||||
@ -261,8 +240,10 @@ the excess bytes are discarded. If there are less then
|
|||||||
<tt>size</tt> bytes available in the current datagram, the
|
<tt>size</tt> bytes available in the current datagram, the
|
||||||
available bytes are returned.
|
available bytes are returned.
|
||||||
If <tt>size</tt> is omitted, the
|
If <tt>size</tt> is omitted, the
|
||||||
<tt>buffersize</tt> argument at creation time is used
|
compile-time constant <a
|
||||||
(which defaults to 8192 bytes).
|
href=socket.html#datagramsize><tt>socket._DATAGRAMSIZE</tt></a> is used
|
||||||
|
(it defaults to 8192 bytes). Larger sizes will cause a
|
||||||
|
temporary buffer to be allocated for the operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="return">
|
<p class="return">
|
||||||
|
@ -39,7 +39,10 @@ static luaL_Reg func[] = {
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int select_open(lua_State *L) {
|
int select_open(lua_State *L) {
|
||||||
lua_pushstring(L, "_SETSIZE");
|
lua_pushstring(L, "_SETSIZE");
|
||||||
lua_pushnumber(L, FD_SETSIZE);
|
lua_pushinteger(L, FD_SETSIZE);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
lua_pushstring(L, "_SOCKETINVALID");
|
||||||
|
lua_pushinteger(L, SOCKET_INVALID);
|
||||||
lua_rawset(L, -3);
|
lua_rawset(L, -3);
|
||||||
luaL_setfuncs(L, func, 0);
|
luaL_setfuncs(L, func, 0);
|
||||||
return 0;
|
return 0;
|
||||||
|
58
src/udp.c
58
src/udp.c
@ -41,7 +41,6 @@ static int meth_setpeername(lua_State *L);
|
|||||||
static int meth_close(lua_State *L);
|
static int meth_close(lua_State *L);
|
||||||
static int meth_setoption(lua_State *L);
|
static int meth_setoption(lua_State *L);
|
||||||
static int meth_getoption(lua_State *L);
|
static int meth_getoption(lua_State *L);
|
||||||
static int meth_getbufferlength(lua_State *L);
|
|
||||||
static int meth_settimeout(lua_State *L);
|
static int meth_settimeout(lua_State *L);
|
||||||
static int meth_getfd(lua_State *L);
|
static int meth_getfd(lua_State *L);
|
||||||
static int meth_setfd(lua_State *L);
|
static int meth_setfd(lua_State *L);
|
||||||
@ -64,7 +63,6 @@ static luaL_Reg udp_methods[] = {
|
|||||||
{"setfd", meth_setfd},
|
{"setfd", meth_setfd},
|
||||||
{"setoption", meth_setoption},
|
{"setoption", meth_setoption},
|
||||||
{"getoption", meth_getoption},
|
{"getoption", meth_getoption},
|
||||||
{"getoption", meth_getbufferlength},
|
|
||||||
{"setpeername", meth_setpeername},
|
{"setpeername", meth_setpeername},
|
||||||
{"setsockname", meth_setsockname},
|
{"setsockname", meth_setsockname},
|
||||||
{"settimeout", meth_settimeout},
|
{"settimeout", meth_settimeout},
|
||||||
@ -118,8 +116,7 @@ static luaL_Reg func[] = {
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int udp_open(lua_State *L)
|
int udp_open(lua_State *L) {
|
||||||
{
|
|
||||||
/* create classes */
|
/* create classes */
|
||||||
auxiliar_newclass(L, "udp{connected}", udp_methods);
|
auxiliar_newclass(L, "udp{connected}", udp_methods);
|
||||||
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
|
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
|
||||||
@ -130,6 +127,10 @@ int udp_open(lua_State *L)
|
|||||||
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
|
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
|
||||||
/* define library functions */
|
/* define library functions */
|
||||||
luaL_setfuncs(L, func, 0);
|
luaL_setfuncs(L, func, 0);
|
||||||
|
/* export default UDP size */
|
||||||
|
lua_pushliteral(L, "_DATAGRAMSIZE");
|
||||||
|
lua_pushinteger(L, UDP_DATAGRAMSIZE);
|
||||||
|
lua_rawset(L, -3);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,30 +206,26 @@ static int meth_sendto(lua_State *L) {
|
|||||||
static int meth_receive(lua_State *L) {
|
static int meth_receive(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
char buf[UDP_DATAGRAMSIZE];
|
char buf[UDP_DATAGRAMSIZE];
|
||||||
size_t len = MAX(udp->len, UDP_DATAGRAMSIZE);
|
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
|
||||||
char *dgram = len > sizeof(buf)? udp->buf: buf;
|
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
|
||||||
size_t got, wanted = (size_t) luaL_optnumber(L, 2, len);
|
|
||||||
int err;
|
int err;
|
||||||
p_timeout tm = &udp->tm;
|
p_timeout tm = &udp->tm;
|
||||||
timeout_markstart(tm);
|
timeout_markstart(tm);
|
||||||
wanted = MIN(wanted, len);
|
if (!dgram) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushliteral(L, "out of memory");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
|
err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
|
||||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||||
if (err != IO_DONE && err != IO_CLOSED ) {
|
if (err != IO_DONE && err != IO_CLOSED) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, udp_strerror(err));
|
lua_pushstring(L, udp_strerror(err));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
lua_pushlstring(L, dgram, got);
|
lua_pushlstring(L, dgram, got);
|
||||||
return 1;
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
|
||||||
* Receives data from a UDP socket
|
|
||||||
\*-------------------------------------------------------------------------*/
|
|
||||||
static int meth_getbufferlength(lua_State *L) {
|
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
|
||||||
lua_pushinteger(L, MAX(UDP_DATAGRAMSIZE, udp->len));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,9 +235,8 @@ static int meth_getbufferlength(lua_State *L) {
|
|||||||
static int meth_receivefrom(lua_State *L) {
|
static int meth_receivefrom(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||||
char buf[UDP_DATAGRAMSIZE];
|
char buf[UDP_DATAGRAMSIZE];
|
||||||
size_t len = MAX(udp->len, UDP_DATAGRAMSIZE);
|
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
|
||||||
char *dgram = len > sizeof(buf)? udp->buf: buf;
|
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
|
||||||
size_t got, wanted = (size_t) luaL_optnumber(L, 2, len);
|
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
socklen_t addr_len = sizeof(addr);
|
socklen_t addr_len = sizeof(addr);
|
||||||
char addrstr[INET6_ADDRSTRLEN];
|
char addrstr[INET6_ADDRSTRLEN];
|
||||||
@ -248,13 +244,18 @@ static int meth_receivefrom(lua_State *L) {
|
|||||||
int err;
|
int err;
|
||||||
p_timeout tm = &udp->tm;
|
p_timeout tm = &udp->tm;
|
||||||
timeout_markstart(tm);
|
timeout_markstart(tm);
|
||||||
wanted = MIN(wanted, len);
|
if (!dgram) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushliteral(L, "out of memory");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
|
err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
|
||||||
&addr_len, tm);
|
&addr_len, tm);
|
||||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||||
if (err != IO_DONE && err != IO_CLOSED) {
|
if (err != IO_DONE && err != IO_CLOSED) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, udp_strerror(err));
|
lua_pushstring(L, udp_strerror(err));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
|
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
|
||||||
@ -262,19 +263,20 @@ static int meth_receivefrom(lua_State *L) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, gai_strerror(err));
|
lua_pushstring(L, gai_strerror(err));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
lua_pushlstring(L, dgram, got);
|
lua_pushlstring(L, dgram, got);
|
||||||
lua_pushstring(L, addrstr);
|
lua_pushstring(L, addrstr);
|
||||||
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
|
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Returns family as string
|
* Returns family as string
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_getfamily(lua_State *L)
|
static int meth_getfamily(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
if (udp->family == AF_INET6) {
|
if (udp->family == AF_INET6) {
|
||||||
lua_pushliteral(L, "inet6");
|
lua_pushliteral(L, "inet6");
|
||||||
@ -419,19 +421,13 @@ static int meth_setsockname(lua_State *L) {
|
|||||||
* Creates a master udp object
|
* Creates a master udp object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int udp_create(lua_State *L, int family) {
|
static int udp_create(lua_State *L, int family) {
|
||||||
p_udp udp = NULL;
|
|
||||||
/* optional length for private datagram buffer. this is useful when
|
|
||||||
* you need larger datagrams than UDP_DATAGRAMSIZE */
|
|
||||||
size_t len = (size_t) luaL_optinteger(L, 1, 0);
|
|
||||||
if (len <= UDP_DATAGRAMSIZE) len = 0;
|
|
||||||
/* allocate udp object */
|
/* allocate udp object */
|
||||||
udp = (p_udp) lua_newuserdata(L, sizeof(t_udp) + len - 1);
|
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
|
||||||
auxiliar_setclass(L, "udp{unconnected}", -1);
|
auxiliar_setclass(L, "udp{unconnected}", -1);
|
||||||
/* if family is AF_UNSPEC, we leave the socket invalid and
|
/* if family is AF_UNSPEC, we leave the socket invalid and
|
||||||
* store AF_UNSPEC into family. This will allow it to later be
|
* store AF_UNSPEC into family. This will allow it to later be
|
||||||
* replaced with an AF_INET6 or AF_INET socket upon first use. */
|
* replaced with an AF_INET6 or AF_INET socket upon first use. */
|
||||||
udp->sock = SOCKET_INVALID;
|
udp->sock = SOCKET_INVALID;
|
||||||
udp->len = len;
|
|
||||||
timeout_init(&udp->tm, -1, -1);
|
timeout_init(&udp->tm, -1, -1);
|
||||||
udp->family = family;
|
udp->family = family;
|
||||||
if (family != AF_UNSPEC) {
|
if (family != AF_UNSPEC) {
|
||||||
|
@ -23,8 +23,6 @@ typedef struct t_udp_ {
|
|||||||
t_socket sock;
|
t_socket sock;
|
||||||
t_timeout tm;
|
t_timeout tm;
|
||||||
int family;
|
int family;
|
||||||
size_t len; /* length of datagram buffer below */
|
|
||||||
char buf[1]; /* allocate larger structure to hold actual buffer */
|
|
||||||
} t_udp;
|
} t_udp;
|
||||||
typedef t_udp *p_udp;
|
typedef t_udp *p_udp;
|
||||||
|
|
||||||
|
@ -669,7 +669,6 @@ local udp_methods = {
|
|||||||
"settimeout"
|
"settimeout"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
test_methods(socket.udp(), udp_methods)
|
test_methods(socket.udp(), udp_methods)
|
||||||
do local sock = socket.tcp6()
|
do local sock = socket.tcp6()
|
||||||
|
Loading…
Reference in New Issue
Block a user