Skip to content

Commit 3c97f39

Browse files
committed
daemon_conn: make it a tal object, typesafe callbacks.
It means an extra allocation at startup, but it means we can hide the definition, and use standard patterns (new_daemon_conn and typesafe callbacks). Signed-off-by: Rusty Russell <[email protected]>
1 parent 0e6aec0 commit 3c97f39

File tree

5 files changed

+226
-213
lines changed

5 files changed

+226
-213
lines changed

common/daemon_conn.c

+57-19
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,40 @@
55
#include <wire/wire_io.h>
66
#include <wire/wire_sync.h>
77

8+
struct daemon_conn {
9+
/* Last message we received */
10+
u8 *msg_in;
11+
12+
/* Queue of outgoing messages */
13+
struct msg_queue out;
14+
15+
/* Underlying connection: we're freed if it closes, and vice versa */
16+
struct io_conn *conn;
17+
18+
/* Callback for incoming messages */
19+
struct io_plan *(*recv)(struct io_conn *conn, const u8 *, void *);
20+
21+
/* Called whenever we've cleared the msg_out queue. If it returns
22+
* true, it has added packets to msg_out queue. */
23+
bool (*outq_empty)(void *);
24+
25+
/* Arg for both callbacks. */
26+
void *arg;
27+
};
28+
29+
static struct io_plan *handle_read(struct io_conn *conn,
30+
struct daemon_conn *dc)
31+
{
32+
return dc->recv(conn, dc->msg_in, dc->arg);
33+
}
34+
835
struct io_plan *daemon_conn_read_next(struct io_conn *conn,
936
struct daemon_conn *dc)
1037
{
11-
dc->msg_in = tal_free(dc->msg_in);
12-
return io_read_wire(conn, dc->ctx, &dc->msg_in, dc->daemon_conn_recv,
13-
dc);
38+
/* FIXME: We could use disposable parent instead, and recv() could
39+
* tal_steal() it? If they did that now, we'd free it here. */
40+
tal_free(dc->msg_in);
41+
return io_read_wire(conn, dc, &dc->msg_in, handle_read, dc);
1442
}
1543

1644
static struct io_plan *daemon_conn_write_next(struct io_conn *conn,
@@ -29,8 +57,8 @@ static struct io_plan *daemon_conn_write_next(struct io_conn *conn,
2957
}
3058
return io_write_wire(conn, take(msg), daemon_conn_write_next,
3159
dc);
32-
} else if (dc->msg_queue_cleared_cb) {
33-
if (dc->msg_queue_cleared_cb(conn, dc))
60+
} else if (dc->outq_empty) {
61+
if (dc->outq_empty(dc->arg))
3462
goto again;
3563
}
3664
return msg_queue_wait(conn, &dc->out, daemon_conn_write_next, dc);
@@ -70,26 +98,36 @@ static struct io_plan *daemon_conn_start(struct io_conn *conn,
7098
struct daemon_conn *dc)
7199
{
72100
return io_duplex(conn, daemon_conn_read_next(conn, dc),
73-
daemon_conn_write_next(conn, dc));
101+
/* Could call daemon_conn_write_next, but we don't
102+
* want it to call empty_cb just yet! */
103+
msg_queue_wait(conn, dc->out,
104+
daemon_conn_write_next, dc));
74105
}
75106

76-
void daemon_conn_init(tal_t *ctx, struct daemon_conn *dc, int fd,
77-
struct io_plan *(*daemon_conn_recv)(struct io_conn *,
78-
struct daemon_conn *))
107+
static void destroy_dc_from_conn(struct io_conn *conn, struct daemon_conn *dc)
79108
{
80-
dc->daemon_conn_recv = daemon_conn_recv;
81-
82-
dc->ctx = ctx;
83-
dc->msg_in = NULL;
84-
msg_queue_init(&dc->out, dc->ctx);
85-
dc->msg_queue_cleared_cb = NULL;
86-
dc->conn = io_new_conn(ctx, fd, daemon_conn_start, dc);
109+
/* Harmless free loop if conn is being destroyed because dc freed */
110+
tal_free(dc);
87111
}
88112

89-
void daemon_conn_clear(struct daemon_conn *dc)
113+
struct daemon_conn *daemon_conn_new_(const tal_t *ctx, int fd,
114+
struct io_plan *(*recv)(struct io_conn *,
115+
const u8 *,
116+
void *),
117+
bool (*outq_empty)(void *),
118+
void *arg)
90119
{
91-
io_set_finish(dc->conn, NULL, NULL);
92-
io_close(dc->conn);
120+
struct daemon_conn *dc = tal(NULL, struct daemon_conn);
121+
122+
dc->recv = recv;
123+
dc->outq_empty = outq_empty;
124+
dc->arg = arg;
125+
dc->msg_in = NULL;
126+
msg_queue_init(&dc->out, dc);
127+
128+
dc->conn = io_new_conn(dc, fd, daemon_conn_start, dc);
129+
tal_add_destructor2(dc->conn, destroy_dc_from_conn, dc);
130+
return dc;
93131
}
94132

95133
void daemon_conn_send(struct daemon_conn *dc, const u8 *msg)

common/daemon_conn.h

+20-39
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,30 @@
66
#include <ccan/short_types/short_types.h>
77
#include <common/msg_queue.h>
88

9-
struct daemon_conn {
10-
/* Context to tallocate all things from, possibly the
11-
* container of this connection. */
12-
tal_t *ctx;
13-
14-
/* Last message we received */
15-
u8 *msg_in;
16-
17-
/* Queue of outgoing messages */
18-
struct msg_queue out;
19-
20-
/* Underlying connection */
21-
struct io_conn *conn;
22-
23-
/* Callback for incoming messages */
24-
struct io_plan *(*daemon_conn_recv)(struct io_conn *conn,
25-
struct daemon_conn *);
26-
27-
/* Called whenever we've cleared the msg_out queue. If it returns
28-
* true, it has added packets to msg_out queue. */
29-
bool (*msg_queue_cleared_cb)(struct io_conn *, struct daemon_conn *);
30-
};
31-
329
/**
33-
* daemon_conn_init - Initialize a new daemon connection
10+
* daemon_conn_new - Allocate a new daemon connection
3411
*
35-
* @ctx: context to allocate from
36-
* @dc: daemon_conn to initialize
12+
* @ctx: context to allocate the daemon_conn's conn from
3713
* @fd: socket file descriptor to wrap
38-
* @daemon_conn_recv: callback function to be called upon receiving a message
39-
*/
40-
void daemon_conn_init(tal_t *ctx, struct daemon_conn *dc, int fd,
41-
struct io_plan *(*daemon_conn_recv)(
42-
struct io_conn *, struct daemon_conn *));
43-
44-
/**
45-
* daemon_conn_clear - discard a daemon conn without triggering finish.
46-
* @dc: the daemon_conn to clean up.
47-
*
48-
* This is used by gossipd when a peer is handed back, and we no longer
49-
* want to deal with it via daemon_conn. @dc must not be used after this!
14+
* @recv: callback function to be called upon receiving a message
15+
* @outq_empty: callback function to be called when queue is empty: returns
16+
* true if it added something to the queue. Can be NULL.
5017
*/
51-
void daemon_conn_clear(struct daemon_conn *dc);
18+
#define daemon_conn_new(ctx, fd, recv, outq_empty, arg) \
19+
daemon_conn_new_((ctx), (fd), \
20+
typesafe_cb_preargs(struct io_plan *, void *, \
21+
(recv), (arg), \
22+
struct io_conn *, \
23+
const u8 *), \
24+
typesafe_cb(bool, void *, (outq_empty), (arg)), \
25+
arg)
26+
27+
struct daemon_conn *daemon_conn_new_(const tal_t *ctx, int fd,
28+
struct io_plan *(*recv)(struct io_conn *,
29+
const u8 *,
30+
void *),
31+
bool (*outq_empty)(void *),
32+
void *arg);
5233

5334
/**
5435
* daemon_conn_send - Enqueue an outgoing message to be sent

connectd/connectd.c

+32-31
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ struct daemon {
121121
struct list_head connecting;
122122

123123
/* Connection to main daemon. */
124-
struct daemon_conn master;
124+
struct daemon_conn *master;
125125

126126
/* Local and global features to offer to peers. */
127127
u8 *localfeatures, *globalfeatures;
@@ -372,7 +372,7 @@ static struct io_plan *peer_reconnected(struct io_conn *conn,
372372

373373
/* Tell master to kill it: will send peer_disconnect */
374374
msg = towire_connect_reconnected(NULL, id);
375-
daemon_conn_send(&daemon->master, take(msg));
375+
daemon_conn_send(daemon->master, take(msg));
376376

377377
/* Save arguments for next time. */
378378
r = tal(daemon, struct peer_reconnected);
@@ -425,10 +425,10 @@ struct io_plan *peer_connected(struct io_conn *conn,
425425
/*~ daemon_conn is a message queue for inter-daemon communication: we
426426
* queue up the `connect_peer_connected` message to tell lightningd
427427
* we have connected, and give the the peer and gossip fds. */
428-
daemon_conn_send(&daemon->master, peer_connected_msg);
428+
daemon_conn_send(daemon->master, peer_connected_msg);
429429
/* io_conn_fd() extracts the fd from ccan/io's io_conn */
430-
daemon_conn_send_fd(&daemon->master, io_conn_fd(conn));
431-
daemon_conn_send_fd(&daemon->master, gossip_fd);
430+
daemon_conn_send_fd(daemon->master, io_conn_fd(conn));
431+
daemon_conn_send_fd(daemon->master, gossip_fd);
432432

433433
/*~ Finally, we add it to the set of pubkeys: tal_dup will handle
434434
* take() args for us, by simply tal_steal()ing it. */
@@ -550,7 +550,7 @@ static void PRINTF_FMT(5,6)
550550
* asking. */
551551
msg = towire_connectctl_connect_failed(NULL, id, err, wait_seconds,
552552
addrhint);
553-
daemon_conn_send(&daemon->master, take(msg));
553+
daemon_conn_send(daemon->master, take(msg));
554554

555555
status_trace("Failed connected out for %s: %s",
556556
type_to_string(tmpctx, struct pubkey, id),
@@ -1080,9 +1080,9 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
10801080
/*~ Parse the incoming connect init message from lightningd ("master") and
10811081
* assign config variables to the daemon; it should be the first message we
10821082
* get. */
1083-
static struct io_plan *connect_init(struct daemon_conn *master,
1084-
struct daemon *daemon,
1085-
const u8 *msg)
1083+
static struct io_plan *connect_init(struct io_conn *conn,
1084+
struct daemon *daemon,
1085+
const u8 *msg)
10861086
{
10871087
struct wireaddr *proxyaddr;
10881088
struct wireaddr_internal *binding;
@@ -1127,19 +1127,19 @@ static struct io_plan *connect_init(struct daemon_conn *master,
11271127
&announcable);
11281128

11291129
/* Tell it we're ready, handing it the addresses we have. */
1130-
daemon_conn_send(&daemon->master,
1130+
daemon_conn_send(daemon->master,
11311131
take(towire_connectctl_init_reply(NULL,
11321132
binding,
11331133
announcable)));
11341134

11351135
/* Read the next message. */
1136-
return daemon_conn_read_next(master->conn, master);
1136+
return daemon_conn_read_next(conn, daemon->master);
11371137
}
11381138

11391139
/*~ lightningd tells us to go! */
1140-
static struct io_plan *connect_activate(struct daemon_conn *master,
1141-
struct daemon *daemon,
1142-
const u8 *msg)
1140+
static struct io_plan *connect_activate(struct io_conn *conn,
1141+
struct daemon *daemon,
1142+
const u8 *msg)
11431143
{
11441144
bool do_listen;
11451145

@@ -1166,9 +1166,9 @@ static struct io_plan *connect_activate(struct daemon_conn *master,
11661166
daemon->listen_fds = tal_free(daemon->listen_fds);
11671167

11681168
/* OK, we're ready! */
1169-
daemon_conn_send(&daemon->master,
1169+
daemon_conn_send(daemon->master,
11701170
take(towire_connectctl_activate_reply(NULL)));
1171-
return daemon_conn_read_next(master->conn, master);
1171+
return daemon_conn_read_next(conn, daemon->master);
11721172
}
11731173

11741174
/*~ This is where we'd put a BOLT #10 reference, but it doesn't exist :( */
@@ -1334,7 +1334,7 @@ static struct io_plan *connect_to_peer(struct io_conn *conn,
13341334
master_badmsg(WIRE_CONNECTCTL_CONNECT_TO_PEER, msg);
13351335

13361336
try_connect_peer(daemon, &id, seconds_waited, addrhint);
1337-
return daemon_conn_read_next(conn, &daemon->master);
1337+
return daemon_conn_read_next(conn, daemon->master);
13381338
}
13391339

13401340
/* lightningd tells us a peer has disconnected. */
@@ -1362,28 +1362,29 @@ static struct io_plan *peer_disconnected(struct io_conn *conn,
13621362
tal_free(key);
13631363

13641364
/* Read the next message from lightningd. */
1365-
return daemon_conn_read_next(conn, &daemon->master);
1365+
return daemon_conn_read_next(conn, daemon->master);
13661366
}
13671367

1368-
static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master)
1368+
static struct io_plan *recv_req(struct io_conn *conn,
1369+
const u8 *msg,
1370+
struct daemon *daemon)
13691371
{
1370-
struct daemon *daemon = container_of(master, struct daemon, master);
1371-
enum connect_wire_type t = fromwire_peektype(master->msg_in);
1372+
enum connect_wire_type t = fromwire_peektype(msg);
13721373

13731374
/* Demux requests from lightningd: we expect INIT then ACTIVATE, then
13741375
* connect requests and disconnected messages. */
13751376
switch (t) {
13761377
case WIRE_CONNECTCTL_INIT:
1377-
return connect_init(master, daemon, master->msg_in);
1378+
return connect_init(conn, daemon, msg);
13781379

13791380
case WIRE_CONNECTCTL_ACTIVATE:
1380-
return connect_activate(master, daemon, master->msg_in);
1381+
return connect_activate(conn, daemon, msg);
13811382

13821383
case WIRE_CONNECTCTL_CONNECT_TO_PEER:
1383-
return connect_to_peer(conn, daemon, master->msg_in);
1384+
return connect_to_peer(conn, daemon, msg);
13841385

13851386
case WIRE_CONNECTCTL_PEER_DISCONNECTED:
1386-
return peer_disconnected(conn, daemon, master->msg_in);
1387+
return peer_disconnected(conn, daemon, msg);
13871388

13881389
/* We send these, we don't receive them */
13891390
case WIRE_CONNECTCTL_INIT_REPLY:
@@ -1396,7 +1397,7 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
13961397

13971398
/* Master shouldn't give bad requests. */
13981399
status_failed(STATUS_FAIL_MASTER_IO, "%i: %s",
1399-
t, tal_hex(tmpctx, master->msg_in));
1400+
t, tal_hex(tmpctx, msg));
14001401
}
14011402

14021403
/*~ Helper for handshake.c: we ask `hsmd` to do the ECDH to get the shared
@@ -1424,8 +1425,7 @@ bool hsm_do_ecdh(struct secret *ss, const struct pubkey *point)
14241425
*
14251426
* The C++ method of omitting unused parameter names is *much* neater, and I
14261427
* hope we'll eventually see it in a C standard. */
1427-
static void master_gone(struct io_conn *unused UNUSED,
1428-
struct daemon *daemon UNUSED)
1428+
static void master_gone(struct daemon_conn *master UNUSED)
14291429
{
14301430
/* Can't tell master, it's gone. */
14311431
exit(2);
@@ -1446,12 +1446,13 @@ int main(int argc, char *argv[])
14461446
list_head_init(&daemon->connecting);
14471447
daemon->listen_fds = tal_arr(daemon, struct listen_fd, 0);
14481448
/* stdin == control */
1449-
daemon_conn_init(daemon, &daemon->master, STDIN_FILENO, recv_req);
1450-
io_set_finish(daemon->master.conn, master_gone, daemon);
1449+
daemon->master = daemon_conn_new(daemon, STDIN_FILENO, recv_req, NULL,
1450+
daemon);
1451+
tal_add_destructor(daemon->master, master_gone);
14511452

14521453
/* This tells the status_* subsystem to use this connection to send
14531454
* our status_ and failed messages. */
1454-
status_setup_async(&daemon->master);
1455+
status_setup_async(daemon->master);
14551456

14561457
/* Should never exit. */
14571458
io_loop(NULL, NULL);

0 commit comments

Comments
 (0)