Skip to content

Commit ff0b56c

Browse files
lnetoclaude
andcommitted
socket: accept data object in send/receive to reuse buffers
sock:send(data [, addr]) -- sends data->ptr/size, no string alloc sock:receive(data [, flags [, from]]) -- receives into data->ptr, returns bytes String path is preserved for backward compatibility. luadata_t is moved to luadata.h and luadata_arg() added for cross-module use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7b23ac5 commit ff0b56c

5 files changed

Lines changed: 50 additions & 34 deletions

File tree

lib/luadata.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616

1717
#include "luadata.h"
1818

19-
20-
typedef struct luadata_s {
21-
void *ptr;
22-
size_t size;
23-
uint8_t opt;
24-
} luadata_t;
25-
2619
#define LUADATA_NUMBER_SZ (sizeof(lua_Integer))
2720

2821
static int luadata_lnew(lua_State *L);

lib/luadata.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,12 @@ static inline void luadata_close(lunatik_object_t *object)
2626

2727
#define luadata_attach(L, obj, field, opt) lunatik_attach(L, obj, field, luadata_new, opt)
2828

29+
typedef struct luadata_s {
30+
void *ptr;
31+
size_t size;
32+
uint8_t opt;
33+
} luadata_t;
34+
35+
2936
#endif
3037

lib/luasocket.c

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#endif
3333

3434
#include <lunatik.h>
35+
#include "luadata.h"
3536

3637
#define luasocket_msgaddr(msg, addr, size) \
3738
do { \
@@ -117,7 +118,7 @@ LUNATIK_PRIVATECHECKER(luasocket_check, struct socket *);
117118
* address family) specify the destination.
118119
*
119120
* @function send
120-
* @tparam string message The string message to send.
121+
* @tparam string|data message The message to send; a data object avoids string allocation.
121122
* @tparam[opt] integer|string addr The destination address.
122123
*
123124
* - For `AF_INET` (IPv4) sockets: An integer representing the IPv4 address (e.g., from `net.aton()`).
@@ -146,7 +147,14 @@ static int luasocket_send(lua_State *L)
146147

147148
luasocket_setmsg(msg);
148149

149-
vec.iov_base = (void *)luaL_checklstring(L, 2, &len);
150+
if (lua_isuserdata(L, 2)) {
151+
luadata_t *data = lunatik_checkclass(L, 2, "data", LUNATIK_OPT_SINGLE)->private;
152+
lunatik_argchecknull(L, data->ptr, 2);
153+
vec.iov_base = data->ptr;
154+
len = data->size;
155+
}
156+
else
157+
vec.iov_base = (void *)luaL_checklstring(L, 2, &len);
150158
vec.iov_len = len;
151159

152160
if (unlikely(nargs >= 3)) {
@@ -163,32 +171,21 @@ static int luasocket_send(lua_State *L)
163171
* Receives a message from the socket.
164172
*
165173
* @function receive
166-
* @tparam integer length The maximum number of bytes to receive.
167-
* @tparam[opt=0] integer flags Optional message flags (e.g., `socket.msg.PEEK`).
168-
* See the `socket.msg` table for available flags. These can be OR'd together.
169-
* @tparam[opt=false] boolean from If `true`, the function also returns the sender's address
170-
* and port (for `AF_INET`). This is typically used with connectionless sockets (`SOCK_DGRAM`).
171-
* @treturn string The received message (as a string of bytes).
172-
* @treturn[opt] integer|string addr If `from` is true, the sender's address.
173-
* - For `AF_INET`: An integer representing the IPv4 address (can be converted with `net.ntoa()`).
174-
* - For other families: A packed string representing the sender's address.
175-
* @treturn[opt] integer port If `from` is true and the family is `AF_INET`, the sender's port number.
174+
* @tparam integer|data buffer Maximum bytes to receive, or a data object to receive into.
175+
* @tparam[opt=0] integer flags Message flags (e.g., `socket.msg.PEEK`).
176+
* @tparam[opt=false] boolean from If `true`, also returns sender address and port (`AF_INET`).
177+
* @treturn string|integer Received bytes as a string, or byte count when a data object is passed.
178+
* @treturn[opt] integer|string addr Sender address if `from` is true.
179+
* @treturn[opt] integer port Sender port if `from` is true and family is `AF_INET`.
176180
* @raise Error if the receive operation fails.
177-
* @usage
178-
* -- For a connected TCP socket:
179-
* local data = tcp_conn_sock:receive(1024)
180-
* if data then print("Received:", data) end
181-
*
182-
* -- For a UDP socket, getting sender info:
183-
* local data, sender_ip_int, sender_port = udp_sock:receive(1500, 0, true)
184-
* if data then print("Received from " .. net.ntoa(sender_ip_int) .. ":" .. sender_port .. ": " .. data) end
185181
* @see socket.msg
186182
* @see net.ntoa
187183
*/
188184
static int luasocket_receive(lua_State *L)
189185
{
190186
struct socket *socket = luasocket_check(L, 1);
191-
size_t len = (size_t)luaL_checkinteger(L, 2);
187+
int isdata = lua_isuserdata(L, 2);
188+
size_t len;
192189
luaL_Buffer B;
193190
struct kvec vec;
194191
struct msghdr msg;
@@ -199,14 +196,23 @@ static int luasocket_receive(lua_State *L)
199196

200197
luasocket_setmsg(msg);
201198

202-
vec.iov_base = (void *)luaL_buffinitsize(L, &B, len);
199+
if (isdata) {
200+
luadata_t *data = lunatik_checkclass(L, 2, "data", LUNATIK_OPT_SINGLE)->private;
201+
lunatik_argchecknull(L, data->ptr, 2);
202+
vec.iov_base = data->ptr;
203+
len = data->size;
204+
}
205+
else {
206+
len = (size_t)luaL_checkinteger(L, 2);
207+
vec.iov_base = (void *)luaL_buffinitsize(L, &B, len);
208+
}
203209
vec.iov_len = len;
204210

205211
if (unlikely(from))
206212
luasocket_msgaddr(msg, addr, sizeof(addr));
207213

208214
lunatik_tryret(L, ret, kernel_recvmsg, socket, &msg, &vec, 1, len, flags);
209-
luaL_pushresultsize(&B, ret);
215+
isdata ? lua_pushinteger(L, ret) : luaL_pushresultsize(&B, ret);
210216

211217
return unlikely(from) ? luasocket_pushaddr(L, (struct sockaddr_storage *)msg.msg_name) + 1 : 1;
212218
}

lunatik.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/mutex.h>
1010
#include <linux/spinlock.h>
1111
#include <linux/slab.h>
12+
#include <linux/string.h>
1213
#include <linux/kref.h>
1314
#include <linux/version.h>
1415

@@ -194,7 +195,7 @@ static inline lunatik_object_t *lunatik_checkruntime(lua_State *L, lunatik_opt_t
194195
#define lunatik_setruntime(L, libname, priv) ((priv)->runtime = lunatik_checkruntime((L), lua##libname##_class.opt))
195196
#define lunatik_monitormt(class, monitor) ((monitor) ? (void *)&(class)->opt : (void *)(class))
196197

197-
static inline void lunatik_checkclass(lua_State *L, const lunatik_class_t *class)
198+
static inline void lunatik_checkcontext(lua_State *L, const lunatik_class_t *class)
198199
{
199200
if (lunatik_cannotsleep(L, !lunatik_issoftirq(class->opt)))
200201
luaL_error(L, "'%s': %s", class->name, LUNATIK_ERR_CONTEXT);
@@ -292,6 +293,15 @@ static inline lunatik_object_t **lunatik_testobject(lua_State *L, int ix)
292293
return (pobject && lunatik_isobject(L, ix, *pobject)) ? pobject : NULL;
293294
}
294295

296+
static inline lunatik_object_t *lunatik_checkclass(lua_State *L, int ix,
297+
const char *name, lunatik_opt_t opt)
298+
{
299+
lunatik_object_t *object = lunatik_checkobject(L, ix);
300+
luaL_argcheck(L, strcmp(object->class->name, name) == 0, ix, name);
301+
luaL_argcheck(L, !opt || (object->opt & opt) == opt, ix, name);
302+
return object;
303+
}
304+
295305
static inline lunatik_object_t **lunatik_checkpobject(lua_State *L, int ix)
296306
{
297307
lunatik_object_t **pobject = lunatik_testobject(L, ix);
@@ -320,7 +330,7 @@ int luaopen_##libname(lua_State *L) \
320330
const lunatik_namespace_t *nss = namespaces; /* avoid -Waddress */ \
321331
luaL_newlib(L, funcs); \
322332
if (cls) { \
323-
lunatik_checkclass(L, cls); \
333+
lunatik_checkcontext(L, cls); \
324334
if (lunatik_ismonitor(cls->opt)) \
325335
lunatik_newclass(L, cls, true); \
326336
lunatik_newclass(L, cls, false); \

lunatik_obj.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ lunatik_object_t *lunatik_newobject(lua_State *L, const lunatik_class_t *class,
2222
lunatik_object_t *object = lunatik_checkalloc(L, sizeof(lunatik_object_t));
2323

2424
/* SOFTIRQ runtime requires a SOFTIRQ class */
25-
lunatik_checkclass(L, class);
25+
lunatik_checkcontext(L, class);
2626

2727
lunatik_setobject(object, class, opt);
2828
lunatik_setclass(L, class, lunatik_ismonitor(object->opt));
@@ -62,7 +62,7 @@ void lunatik_cloneobject(lua_State *L, lunatik_object_t *object)
6262
lunatik_require(L, class->name);
6363
lunatik_object_t **pobject = lunatik_newpobject(L, 1);
6464

65-
lunatik_checkclass(L, class);
65+
lunatik_checkcontext(L, class);
6666
lunatik_setclass(L, class, lunatik_ismonitor(object->opt));
6767
*pobject = object;
6868
}

0 commit comments

Comments
 (0)