mirror of
https://github.com/troglobit/finit.git
synced 2026-10-22 11:36:07 +00:00
libink: let a handler park its call and reply later
The park machinery was welded to broker uid resolution; a handler that cannot answer yet, like a device-settle call waiting for the event queue to drain, had no way to defer. link_call_park() holds the request, link_call_resume() re-runs the handler with link_call_resumed() reading true, and the expire sweep remains the backstop for a resume that never comes. Resume also no longer drops a local caller's kernel group set in the privileged re-check: group source now keys on broker-ness. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
4 files changed
+88
-11
No files matched your search
+68
-9
@@ -393,6 +393,7 @@ static struct link_parked *park(link_connection_t *conn, const uint8_t *frame,
|
||||
bus->parked[i].tok = ++bus->next_tok;
|
||||
bus->parked[i].conn = conn;
|
||||
bus->parked[i].stamp = __now_ms();
|
||||
bus->parked[i].uid = (uid_t)-1;
|
||||
bus->parked[i].len = len;
|
||||
memcpy(bus->parked[i].buf, frame, len);
|
||||
*tok = bus->parked[i].tok;
|
||||
@@ -477,13 +478,20 @@ void __dispatch_forget_conn(link_connection_t *conn)
|
||||
|
||||
static int dispatch_call(link_connection_t *conn, const struct link_msg *m,
|
||||
const uint8_t *frame, size_t framelen,
|
||||
const uid_t *known_uid);
|
||||
const uid_t *known_uid, int resumed);
|
||||
|
||||
void link_uid_resolved(link_connection_t *conn, link_authz_t tok, uid_t uid)
|
||||
/*
|
||||
* Shared resume: copy the parked frame out, free the slot, re-enter
|
||||
* dispatch. `uid` NULL means "use what the slot recorded" (a
|
||||
* handler-parked call); non-NULL is a resolver's answer.
|
||||
*/
|
||||
static void resume_parked(link_connection_t *conn, link_authz_t tok,
|
||||
const uid_t *uid, int resumed)
|
||||
{
|
||||
uint8_t buf[LINK_PARKED_MSG_MAX];
|
||||
struct link_parked *p = NULL;
|
||||
struct link_msg msg;
|
||||
uid_t slot_uid;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
@@ -501,15 +509,58 @@ void link_uid_resolved(link_connection_t *conn, link_authz_t tok, uid_t uid)
|
||||
|
||||
/* Copy the message out and free the slot before dispatching:
|
||||
* the handler may park a call of its own. */
|
||||
len = p->len;
|
||||
len = p->len;
|
||||
slot_uid = p->uid;
|
||||
memcpy(buf, p->buf, len);
|
||||
unpark(p);
|
||||
|
||||
if (__msg_parse(buf, len, &msg) <= 0)
|
||||
return;
|
||||
|
||||
__dbg("resumed %s, caller uid %d", msg.member ? msg.member : "call", (int)uid);
|
||||
(void)dispatch_call(conn, &msg, NULL, 0, &uid);
|
||||
if (!uid)
|
||||
uid = &slot_uid;
|
||||
|
||||
__dbg("resumed %s, caller uid %d", msg.member ? msg.member : "call", (int)*uid);
|
||||
(void)dispatch_call(conn, &msg, NULL, 0, uid, resumed);
|
||||
}
|
||||
|
||||
void link_uid_resolved(link_connection_t *conn, link_authz_t tok, uid_t uid)
|
||||
{
|
||||
resume_parked(conn, tok, &uid, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Defer the reply: hold the request and re-run the handler later via
|
||||
* link_call_resume(), where link_call_resumed() reads true. A resumed
|
||||
* call cannot park again -- the raw frame is gone -- so the handler
|
||||
* must answer on the second run. link_connection_expire() is the
|
||||
* backstop for a resume that never comes.
|
||||
*/
|
||||
int link_call_park(link_call_t *call, link_authz_t *tok)
|
||||
{
|
||||
struct link_parked *p;
|
||||
|
||||
if (!call || !tok || call->resumed)
|
||||
return -1;
|
||||
|
||||
p = park(call->conn, call->frame, call->framelen, tok);
|
||||
if (!p)
|
||||
return -1;
|
||||
|
||||
p->uid = call->uid;
|
||||
call->parked = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void link_call_resume(link_connection_t *conn, link_authz_t tok)
|
||||
{
|
||||
resume_parked(conn, tok, NULL, 1);
|
||||
}
|
||||
|
||||
int link_call_resumed(const link_call_t *call)
|
||||
{
|
||||
return call ? call->resumed : 0;
|
||||
}
|
||||
|
||||
int __dispatch_message(link_connection_t *conn, const struct link_msg *m, size_t framelen)
|
||||
@@ -524,7 +575,7 @@ int __dispatch_message(link_connection_t *conn, const struct link_msg *m, size_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dispatch_call(conn, m, conn->rxbuf, framelen, NULL);
|
||||
return dispatch_call(conn, m, conn->rxbuf, framelen, NULL, 0);
|
||||
}
|
||||
|
||||
/* Who may invoke a privileged method. Without an authorizer, only
|
||||
@@ -582,7 +633,7 @@ static int resolve_caller(link_connection_t *conn, const struct link_msg *m,
|
||||
|
||||
static int dispatch_call(link_connection_t *conn, const struct link_msg *m,
|
||||
const uint8_t *frame, size_t framelen,
|
||||
const uid_t *known_uid)
|
||||
const uid_t *known_uid, int resumed)
|
||||
{
|
||||
struct link_object *o;
|
||||
struct link_vtable_entry *e = NULL;
|
||||
@@ -676,8 +727,8 @@ static int dispatch_call(link_connection_t *conn, const struct link_msg *m,
|
||||
* resolved over a broker carries only its uid, so the
|
||||
* authorizer sees no groups and falls back to root-only. */
|
||||
if (!caller_may(conn->server, call_uid,
|
||||
known_uid ? NULL : conn->peer_groups,
|
||||
known_uid ? 0 : conn->peer_ngroups)) {
|
||||
conn->broker ? NULL : conn->peer_groups,
|
||||
conn->broker ? 0 : conn->peer_ngroups)) {
|
||||
__dbg("denied %s, caller uid %d is not privileged",
|
||||
m->member, (int)call_uid);
|
||||
return __send_error(conn, m,
|
||||
@@ -690,10 +741,18 @@ static int dispatch_call(link_connection_t *conn, const struct link_msg *m,
|
||||
call.conn = conn;
|
||||
call.uid = call_uid;
|
||||
call.incoming = *m;
|
||||
call.frame = frame;
|
||||
call.framelen = framelen;
|
||||
call.resumed = resumed;
|
||||
__r_init(&call.read_cursor, m->body, m->body_avail);
|
||||
|
||||
rc = meth->handler(&call, e->userdata);
|
||||
|
||||
/* The handler parked the call: no reply yet, it is resumed via
|
||||
* link_call_resume() or expired by link_connection_expire(). */
|
||||
if (call.parked)
|
||||
return 0;
|
||||
|
||||
/* Every path returns the status of whatever it put on the wire,
|
||||
* so a failed send propagates out and the read loop drops the
|
||||
* peer rather than leaving a half-written frame on a live link.
|
||||
|
||||
Reference in new issue
Block a user