#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int status_fd = -1; static struct daemon_conn *status_conn; const void *trc; volatile bool logging_io = false; static void got_sigusr1(int signal) { 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); } void status_setup_sync(int fd) { assert(status_fd == -1); assert(!status_conn); status_fd = fd; trc = tal_tmpctx(NULL); setup_logging_sighandler(); } void status_setup_async(struct daemon_conn *master) { assert(status_fd == -1); assert(!status_conn); status_conn = master; /* Don't use tmpctx here, otherwise debug_poll gets upset. */ trc = tal(NULL, char); setup_logging_sighandler(); } static void status_send(const u8 *msg TAKES) { 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 u8 *p) { status_send(take(towire_status_io(NULL, iodir, p))); } static void status_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_io(enum log_level iodir, const u8 *p) { if (logging_io) status_io_full(iodir, p); else status_io_short(iodir, p); } 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); /* Free up any temporary children. */ if (tal_first(trc)) { tal_free(trc); trc = tal(NULL, char); } } 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)); } /* 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; breakpoint(); va_start(ap, fmt); str = tal_vfmt(NULL, fmt, ap); status_send(take(towire_status_fail(NULL, reason, str))); va_end(ap); flush_and_exit(reason); } 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(trc, msg)); } void status_fatal_connection_lost(void) { status_send(take(towire_status_peer_connection_lost(NULL))); flush_and_exit(WIRE_STATUS_PEER_CONNECTION_LOST); } /* Got an error for one or all channels */ void status_fatal_received_errmsg(const char *desc, const struct channel_id *c) { static const struct channel_id all_channels; if (!c) c = &all_channels; status_send(take(towire_status_received_errmsg(NULL, c, desc))); flush_and_exit(WIRE_STATUS_RECEIVED_ERRMSG); } /* Sent an error for one or all channels */ void status_fatal_sent_errmsg(const u8 *errmsg, const char *desc, const struct channel_id *c) { static const struct channel_id all_channels; if (!c) c = &all_channels; status_send(take(towire_status_sent_errmsg(NULL, c, desc, errmsg))); flush_and_exit(WIRE_STATUS_SENT_ERRMSG); }