libnl: recvmsgs doesn't necessarily free the message data
I stepped over libnl always freeing the messages and it kind of made it awkward to reuse the message data without reallocating. The basic idea is: if a callback return value has a bit set, don't free that message. The calling application owns it. By default, things stay as before (messages are freed). Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
This commit is contained in:
parent
535e831622
commit
32000e8e9c
2 changed files with 36 additions and 3 deletions
|
@ -64,6 +64,20 @@ enum nl_cb_action {
|
|||
NL_STOP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback action modifiers
|
||||
* @ingroup cb
|
||||
*
|
||||
* These should be ORed to the callback actions defined by enum
|
||||
* nl_cb_action.
|
||||
*/
|
||||
enum nl_cb_action_mods {
|
||||
/** Callee keeps the message, don't free */
|
||||
NL_KEEP_MSG = 0x1000,
|
||||
#define NL_KEEP_MSG NL_KEEP_MSG /* for config testing */
|
||||
};
|
||||
|
||||
|
||||
/* backwards compatibility */
|
||||
#define NL_PROCEED NL_OK
|
||||
#define NL_EXIT NL_STOP
|
||||
|
|
25
lib/nl.c
25
lib/nl.c
|
@ -551,6 +551,9 @@ abort:
|
|||
#define NL_CB_CALL(cb, type, msg) \
|
||||
do { \
|
||||
err = nl_cb_call(cb, type, msg); \
|
||||
if (free_msg && (err & NL_KEEP_MSG)) \
|
||||
free_msg = 0; \
|
||||
err &= ~NL_KEEP_MSG; \
|
||||
switch (err) { \
|
||||
case NL_OK: \
|
||||
err = 0; \
|
||||
|
@ -564,10 +567,23 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* NOTE: on handling freeing of the message data
|
||||
*
|
||||
* By default, the message data is freed after handling is done. In
|
||||
* order to allow a callback using it after exiting the message
|
||||
* handling loop, it can return NL_KEEP_MSG ORed to it's return code.
|
||||
*
|
||||
* Once the freeing of the message is disabled, it cannot be activated
|
||||
* again; this way, if a callback decides to switch it off because it
|
||||
* will keep the allocated data, another one cannot activate it, have
|
||||
* it freed and cause a race condition with later access to that (now
|
||||
* freed) data.
|
||||
*/
|
||||
static int recvmsgs(struct nl_handle *handle, struct nl_cb *cb)
|
||||
{
|
||||
int n, err = 0, multipart = 0;
|
||||
unsigned char *buf = NULL;
|
||||
unsigned char *buf = NULL, free_msg = 1;
|
||||
struct nlmsghdr *hdr;
|
||||
struct sockaddr_nl nla = {0};
|
||||
struct nl_msg *msg = NULL;
|
||||
|
@ -590,7 +606,9 @@ continue_reading:
|
|||
NL_DBG(3, "recgmsgs(%p): Processing valid message...\n",
|
||||
handle);
|
||||
|
||||
nlmsg_free(msg);
|
||||
if (free_msg)
|
||||
nlmsg_free(msg);
|
||||
free_msg = 1; /* By default, we free the message data */
|
||||
msg = nlmsg_convert(hdr);
|
||||
if (!msg) {
|
||||
err = nl_errno(ENOMEM);
|
||||
|
@ -728,7 +746,8 @@ skip:
|
|||
hdr = nlmsg_next(hdr, &n);
|
||||
}
|
||||
|
||||
nlmsg_free(msg);
|
||||
if (free_msg)
|
||||
nlmsg_free(msg);
|
||||
free(buf);
|
||||
free(creds);
|
||||
buf = NULL;
|
||||
|
|
Loading…
Add table
Reference in a new issue