diff --git a/lightningd/Makefile b/lightningd/Makefile index 7b6512f66..3a6388f10 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -51,6 +51,7 @@ LIGHTNINGD_SRC := \ lightningd/build_utxos.c \ lightningd/chaintopology.c \ lightningd/channel.c \ + lightningd/connect_control.c \ lightningd/gossip_control.c \ lightningd/gossip_msg.c \ lightningd/hsm_control.c \ diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c new file mode 100644 index 000000000..0b8a36579 --- /dev/null +++ b/lightningd/connect_control.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct connect { + struct list_node list; + struct pubkey id; + struct command *cmd; +}; + +static void destroy_connect(struct connect *c) +{ + list_del(&c->list); +} + +static struct connect *new_connect(struct lightningd *ld, + const struct pubkey *id, + struct command *cmd) +{ + struct connect *c = tal(cmd, struct connect); + c->id = *id; + c->cmd = cmd; + list_add(&ld->connects, &c->list); + tal_add_destructor(c, destroy_connect); + return c; +} + +void connect_succeeded(struct lightningd *ld, const struct pubkey *id) +{ + struct connect *i, *next; + + /* Careful! Completing command frees connect. */ + list_for_each_safe(&ld->connects, i, next, list) { + struct json_result *response; + + if (!pubkey_eq(&i->id, id)) + continue; + + response = new_json_result(i->cmd); + json_object_start(response, NULL); + json_add_pubkey(response, "id", id); + json_object_end(response); + command_success(i->cmd, response); + } +} + +void connect_failed(struct lightningd *ld, const struct pubkey *id, + const char *error) +{ + struct connect *i, *next; + + /* Careful! Completing command frees connect. */ + list_for_each_safe(&ld->connects, i, next, list) { + if (pubkey_eq(&i->id, id)) + command_fail(i->cmd, "%s", error); + } +} + +void peer_connection_failed(struct lightningd *ld, const u8 *msg) +{ + struct pubkey id; + u32 attempts, timediff; + bool addr_unknown; + char *error; + + if (!fromwire_gossip_peer_connection_failed(msg, NULL, &id, &timediff, + &attempts, &addr_unknown)) + fatal( + "Gossip gave bad GOSSIP_PEER_CONNECTION_FAILED message %s", + tal_hex(msg, msg)); + + if (addr_unknown) { + error = tal_fmt( + msg, "No address known for node %s, please provide one", + type_to_string(msg, struct pubkey, &id)); + } else { + error = tal_fmt(msg, "Could not connect to %s after %d seconds and %d attempts", + type_to_string(msg, struct pubkey, &id), timediff, + attempts); + } + + connect_failed(ld, &id, error); +} + +static void json_connect(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + jsmntok_t *hosttok, *porttok, *idtok; + struct pubkey id; + char *id_str; + char *atptr; + char *ataddr = NULL; + int atidx; + const char *name; + struct wireaddr addr; + u8 *msg; + + if (!json_get_params(cmd, buffer, params, + "id", &idtok, + "?host", &hosttok, + "?port", &porttok, + NULL)) { + return; + } + + /* Check for id@addrport form */ + id_str = tal_strndup(cmd, buffer + idtok->start, + idtok->end - idtok->start); + atptr = strchr(id_str, '@'); + if (atptr) { + atidx = atptr - id_str; + ataddr = tal_strdup(cmd, atptr + 1); + /* Cut id. */ + idtok->end = idtok->start + atidx; + } + + if (!json_tok_pubkey(buffer, idtok, &id)) { + command_fail(cmd, "id %.*s not valid", + idtok->end - idtok->start, + buffer + idtok->start); + return; + } + + if (hosttok && ataddr) { + command_fail(cmd, + "Can't specify host as both xxx@yyy " + "and separate argument"); + return; + } + + /* Get parseable host if provided somehow */ + if (hosttok) + name = tal_strndup(cmd, buffer + hosttok->start, + hosttok->end - hosttok->start); + else if (ataddr) + name = ataddr; + else + name = NULL; + + /* Port without host name? */ + if (porttok && !name) { + command_fail(cmd, "Can't specify port without host"); + return; + } + + /* Was there parseable host name? */ + if (name) { + /* Is there a port? */ + if (porttok) { + u32 port; + if (!json_tok_number(buffer, porttok, &port)) { + command_fail(cmd, "Port %.*s not valid", + porttok->end - porttok->start, + buffer + porttok->start); + return; + } + addr.port = port; + } else { + addr.port = DEFAULT_PORT; + } + if (!parse_wireaddr(name, &addr, addr.port) || !addr.port) { + command_fail(cmd, "Host %s:%u not valid", + name, addr.port); + return; + } + + /* Tell it about the address. */ + msg = towire_gossipctl_peer_addrhint(cmd, &id, &addr); + subd_send_msg(cmd->ld->gossip, take(msg)); + } + + /* Now tell it to try reaching it. */ + msg = towire_gossipctl_reach_peer(cmd, &id); + subd_send_msg(cmd->ld->gossip, take(msg)); + + /* Leave this here for gossip_peer_connected */ + new_connect(cmd->ld, &id, cmd); + command_still_pending(cmd); +} + +static const struct json_command connect_command = { + "connect", + json_connect, + "Connect to {id} at {host} (which can end in ':port' if not default). " + "{id} can also be of the form id@host" +}; +AUTODATA(json_command, &connect_command); diff --git a/lightningd/connect_control.h b/lightningd/connect_control.h new file mode 100644 index 000000000..f489001f1 --- /dev/null +++ b/lightningd/connect_control.h @@ -0,0 +1,15 @@ +#ifndef LIGHTNING_LIGHTNINGD_CONNECT_CONTROL_H +#define LIGHTNING_LIGHTNINGD_CONNECT_CONTROL_H +#include "config.h" + +struct lightningd; +struct pubkey; + +void connect_succeeded(struct lightningd *ld, const struct pubkey *id); +void connect_failed(struct lightningd *ld, const struct pubkey *id, + const char *error); + +/* Gossipd was unable to connect to the peer */ +void peer_connection_failed(struct lightningd *ld, const u8 *msg); + +#endif /* LIGHTNING_LIGHTNINGD_CONNECT_CONTROL_H */ diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 6b624e8a7..b199a0dd6 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 7497cb958..9fa75e0b6 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -45,12 +46,6 @@ #include #include -struct connect { - struct list_node list; - struct pubkey id; - struct command *cmd; -}; - /* FIXME: Reorder */ static void copy_to_parent_log(const char *prefix, enum log_level level, @@ -167,54 +162,6 @@ void drop_to_chain(struct lightningd *ld, struct channel *channel) remove_sig(channel->last_tx); } -static void destroy_connect(struct connect *c) -{ - list_del(&c->list); -} - -static struct connect *new_connect(struct lightningd *ld, - const struct pubkey *id, - struct command *cmd) -{ - struct connect *c = tal(cmd, struct connect); - c->id = *id; - c->cmd = cmd; - list_add(&ld->connects, &c->list); - tal_add_destructor(c, destroy_connect); - return c; -} - -static void connect_succeeded(struct lightningd *ld, const struct pubkey *id) -{ - struct connect *i, *next; - - /* Careful! Completing command frees connect. */ - list_for_each_safe(&ld->connects, i, next, list) { - struct json_result *response; - - if (!pubkey_eq(&i->id, id)) - continue; - - response = new_json_result(i->cmd); - json_object_start(response, NULL); - json_add_pubkey(response, "id", id); - json_object_end(response); - command_success(i->cmd, response); - } -} - -static void connect_failed(struct lightningd *ld, const struct pubkey *id, - const char *error) -{ - struct connect *i, *next; - - /* Careful! Completing command frees connect. */ - list_for_each_safe(&ld->connects, i, next, list) { - if (pubkey_eq(&i->id, id)) - command_fail(i->cmd, "%s", error); - } -} - static void channel_errmsg(struct channel *channel, int peer_fd, int gossip_fd, const struct crypto_state *cs, @@ -413,39 +360,6 @@ void peer_already_connected(struct lightningd *ld, const u8 *msg) connect_succeeded(ld, &id); } -void peer_connection_failed(struct lightningd *ld, const u8 *msg) -{ - struct pubkey id; - u32 attempts, timediff; - struct connect *i, *next; - bool addr_unknown; - char *error; - - if (!fromwire_gossip_peer_connection_failed(msg, NULL, &id, &timediff, - &attempts, &addr_unknown)) - fatal( - "Gossip gave bad GOSSIP_PEER_CONNECTION_FAILED message %s", - tal_hex(msg, msg)); - - if (addr_unknown) { - error = tal_fmt( - msg, "No address known for node %s, please provide one", - type_to_string(msg, struct pubkey, &id)); - } else { - error = tal_fmt(msg, "Could not connect to %s after %d seconds and %d attempts", - type_to_string(msg, struct pubkey, &id), timediff, - attempts); - } - - /* Careful! Completing command frees connect. */ - list_for_each_safe(&ld->connects, i, next, list) { - if (!pubkey_eq(&i->id, &id)) - continue; - - command_fail(i->cmd, "%s", error); - } -} - static struct channel *channel_by_channel_id(struct peer *peer, const struct channel_id *channel_id) { @@ -549,110 +463,6 @@ struct peer *peer_by_id(struct lightningd *ld, const struct pubkey *id) return NULL; } -static void json_connect(struct command *cmd, - const char *buffer, const jsmntok_t *params) -{ - jsmntok_t *hosttok, *porttok, *idtok; - struct pubkey id; - char *id_str; - char *atptr; - char *ataddr = NULL; - int atidx; - const char *name; - struct wireaddr addr; - u8 *msg; - - if (!json_get_params(cmd, buffer, params, - "id", &idtok, - "?host", &hosttok, - "?port", &porttok, - NULL)) { - return; - } - - /* Check for id@addrport form */ - id_str = tal_strndup(cmd, buffer + idtok->start, - idtok->end - idtok->start); - atptr = strchr(id_str, '@'); - if (atptr) { - atidx = atptr - id_str; - ataddr = tal_strdup(cmd, atptr + 1); - /* Cut id. */ - idtok->end = idtok->start + atidx; - } - - if (!json_tok_pubkey(buffer, idtok, &id)) { - command_fail(cmd, "id %.*s not valid", - idtok->end - idtok->start, - buffer + idtok->start); - return; - } - - if (hosttok && ataddr) { - command_fail(cmd, - "Can't specify host as both xxx@yyy " - "and separate argument"); - return; - } - - /* Get parseable host if provided somehow */ - if (hosttok) - name = tal_strndup(cmd, buffer + hosttok->start, - hosttok->end - hosttok->start); - else if (ataddr) - name = ataddr; - else - name = NULL; - - /* Port without host name? */ - if (porttok && !name) { - command_fail(cmd, "Can't specify port without host"); - return; - } - - /* Was there parseable host name? */ - if (name) { - /* Is there a port? */ - if (porttok) { - u32 port; - if (!json_tok_number(buffer, porttok, &port)) { - command_fail(cmd, "Port %.*s not valid", - porttok->end - porttok->start, - buffer + porttok->start); - return; - } - addr.port = port; - } else { - addr.port = DEFAULT_PORT; - } - if (!parse_wireaddr(name, &addr, addr.port) || !addr.port) { - command_fail(cmd, "Host %s:%u not valid", - name, addr.port); - return; - } - - /* Tell it about the address. */ - msg = towire_gossipctl_peer_addrhint(cmd, &id, &addr); - subd_send_msg(cmd->ld->gossip, take(msg)); - } - - /* Now tell it to try reaching it. */ - msg = towire_gossipctl_reach_peer(cmd, &id); - subd_send_msg(cmd->ld->gossip, take(msg)); - - /* Leave this here for gossip_peer_connected */ - new_connect(cmd->ld, &id, cmd); - command_still_pending(cmd); -} - -static const struct json_command connect_command = { - "connect", - json_connect, - "Connect to {id} at {host} (which can end in ':port' if not default). " - "{id} can also be of the form id@host" -}; -AUTODATA(json_command, &connect_command); - struct getpeers_args { struct command *cmd; /* If non-NULL, they want logs too */ diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 2fbe8797c..015b4ba07 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -74,9 +74,6 @@ void peer_connected(struct lightningd *ld, const u8 *msg, /* This simply means we asked to reach a peer, but we already have it */ void peer_already_connected(struct lightningd *ld, const u8 *msg); -/* We were unable to connect to the peer */ -void peer_connection_failed(struct lightningd *ld, const u8 *msg); - void peer_sent_nongossip(struct lightningd *ld, const struct pubkey *id, const struct wireaddr *addr, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 1a2d2e6cb..ea7b24357 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -62,6 +62,13 @@ void command_still_pending(struct command *cmd UNNEEDED) /* Generated stub for command_success */ void command_success(struct command *cmd UNNEEDED, struct json_result *response UNNEEDED) { fprintf(stderr, "command_success called!\n"); abort(); } +/* Generated stub for connect_failed */ +void connect_failed(struct lightningd *ld UNNEEDED, const struct pubkey *id UNNEEDED, + const char *error UNNEEDED) +{ fprintf(stderr, "connect_failed called!\n"); abort(); } +/* Generated stub for connect_succeeded */ +void connect_succeeded(struct lightningd *ld UNNEEDED, const struct pubkey *id UNNEEDED) +{ fprintf(stderr, "connect_succeeded called!\n"); abort(); } /* Generated stub for derive_basepoints */ bool derive_basepoints(const struct privkey *seed UNNEEDED, struct pubkey *funding_pubkey UNNEEDED, @@ -105,9 +112,6 @@ bool fromwire_gossip_peer_already_connected(const void *p UNNEEDED, size_t *plen /* Generated stub for fromwire_gossip_peer_connected */ bool fromwire_gossip_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, size_t *plen UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u64 *gossip_index UNNEEDED, u8 **gfeatures UNNEEDED, u8 **lfeatures UNNEEDED) { fprintf(stderr, "fromwire_gossip_peer_connected called!\n"); abort(); } -/* Generated stub for fromwire_gossip_peer_connection_failed */ -bool fromwire_gossip_peer_connection_failed(const void *p UNNEEDED, size_t *plen UNNEEDED, struct pubkey *id UNNEEDED, u32 *timeout UNNEEDED, u32 *attempts UNNEEDED, bool *addr_unknown UNNEEDED) -{ fprintf(stderr, "fromwire_gossip_peer_connection_failed called!\n"); abort(); } /* Generated stub for fromwire_hsm_client_hsmfd_reply */ bool fromwire_hsm_client_hsmfd_reply(const void *p UNNEEDED, size_t *plen UNNEEDED) { fprintf(stderr, "fromwire_hsm_client_hsmfd_reply called!\n"); abort(); } @@ -261,10 +265,6 @@ bool json_tok_bool(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, b bool json_tok_loglevel(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, enum log_level *level UNNEEDED) { fprintf(stderr, "json_tok_loglevel called!\n"); abort(); } -/* Generated stub for json_tok_number */ -bool json_tok_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - unsigned int *num UNNEEDED) -{ fprintf(stderr, "json_tok_number called!\n"); abort(); } /* Generated stub for json_tok_pubkey */ bool json_tok_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct pubkey *pubkey UNNEEDED)