forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
status.c
183 lines (156 loc) · 4.12 KB
/
status.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <assert.h>
#include <ccan/breakpoint/breakpoint.h>
#include <ccan/endian/endian.h>
#include <ccan/err/err.h>
#include <ccan/fdpass/fdpass.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/tal/str/str.h>
#include <common/daemon_conn.h>
#include <common/gen_status_wire.h>
#include <common/status.h>
#include <common/utils.h>
#include <errno.h>
#include <signal.h>
#include <wire/peer_wire.h>
#include <wire/wire_sync.h>
static int status_fd = -1;
static struct daemon_conn *status_conn;
volatile bool logging_io = false;
static bool was_logging_io = false;
static void got_sigusr1(int signal UNUSED)
{
logging_io = !logging_io;
}
static void setup_logging_sighandler(void)
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = got_sigusr1;
act.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &act, NULL);
}
static void report_logging_io(const char *why)
{
if (logging_io != was_logging_io) {
was_logging_io = logging_io;
status_trace("%s: IO LOGGING %s",
why, logging_io ? "ENABLED" : "DISABLED");
}
}
void status_setup_sync(int fd)
{
assert(status_fd == -1);
assert(!status_conn);
status_fd = fd;
setup_logging_sighandler();
#if DEVELOPER
logging_io = (getenv("LIGHTNINGD_DEV_LOG_IO") != NULL);
report_logging_io("LIGHTNINGD_DEV_LOG_IO");
#endif
}
void status_setup_async(struct daemon_conn *master)
{
assert(status_fd == -1);
assert(!status_conn);
status_conn = master;
setup_logging_sighandler();
#if DEVELOPER
logging_io = (getenv("LIGHTNINGD_DEV_LOG_IO") != NULL);
report_logging_io("LIGHTNINGD_DEV_LOG_IO");
#endif
}
void status_send(const u8 *msg TAKES)
{
report_logging_io("SIGUSR1");
if (status_fd >= 0) {
int type =fromwire_peektype(msg);
if (!wire_sync_write(status_fd, msg))
err(1, "Writing out status %i", type);
} else {
daemon_conn_send(status_conn, msg);
}
}
static void status_io_full(enum log_level iodir, const char *who, const u8 *p)
{
status_send(take(towire_status_io(NULL, iodir, who, p)));
}
static void status_peer_io_short(enum log_level iodir, const u8 *p)
{
status_debug("%s %s",
iodir == LOG_IO_OUT ? "peer_out" : "peer_in",
wire_type_name(fromwire_peektype(p)));
}
void status_peer_io(enum log_level iodir, const u8 *p)
{
report_logging_io("SIGUSR1");
if (logging_io)
status_io_full(iodir, "", p);
/* We get a huge amount of gossip; don't log it */
else if (!is_msg_for_gossipd(p))
status_peer_io_short(iodir, p);
}
void status_io(enum log_level iodir, const char *who,
const void *data, size_t len)
{
report_logging_io("SIGUSR1");
if (!logging_io)
return;
/* Horribly inefficient, but so is logging IO generally. */
status_io_full(iodir, who, tal_dup_arr(tmpctx, u8, data, len, 0));
}
void status_vfmt(enum log_level level, const char *fmt, va_list ap)
{
char *str;
str = tal_vfmt(NULL, fmt, ap);
status_send(take(towire_status_log(NULL, level, str)));
tal_free(str);
}
void status_fmt(enum log_level level, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
status_vfmt(level, fmt, ap);
va_end(ap);
}
static NORETURN void flush_and_exit(int reason)
{
/* Don't let it take forever. */
alarm(10);
if (status_conn)
daemon_conn_sync_flush(status_conn);
exit(0x80 | (reason & 0xFF));
}
void status_send_fatal(const u8 *msg TAKES, int fd1, int fd2)
{
int reason = fromwire_peektype(msg);
breakpoint();
status_send(msg);
/* We don't support async fd passing here. */
if (fd1 != -1) {
assert(!status_conn);
fdpass_send(status_fd, fd1);
fdpass_send(status_fd, fd2);
}
flush_and_exit(reason);
}
/* FIXME: rename to status_fatal, s/fail/fatal/ in status_failreason enums */
void status_failed(enum status_failreason reason, const char *fmt, ...)
{
va_list ap;
char *str;
va_start(ap, fmt);
str = tal_vfmt(NULL, fmt, ap);
va_end(ap);
status_send_fatal(take(towire_status_fail(NULL, reason, str)),
-1, -1);
}
void master_badmsg(u32 type_expected, const u8 *msg)
{
if (!msg)
status_failed(STATUS_FAIL_MASTER_IO,
"failed reading msg %u: %s",
type_expected, strerror(errno));
status_failed(STATUS_FAIL_MASTER_IO,
"Error parsing %u: %s",
type_expected, tal_hex(tmpctx, msg));
}