From cbf51a7f823908035a2a723789cda984908c63f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 16 Aug 2019 15:55:58 +0200 Subject: [PATCH] Support Broadcast in Regist --- gui/include/registdialog.h | 2 + gui/src/registdialog.cpp | 6 ++ lib/include/chiaki/regist.h | 2 +- lib/src/discovery.c | 18 +----- lib/src/regist.c | 106 ++++++++++++++++++++++++++---------- lib/src/utils.h | 21 +++++++ 6 files changed, 109 insertions(+), 46 deletions(-) diff --git a/gui/include/registdialog.h b/gui/include/registdialog.h index 332e6d6..3171b92 100644 --- a/gui/include/registdialog.h +++ b/gui/include/registdialog.h @@ -29,6 +29,7 @@ class Settings; class QLineEdit; class QPlainTextEdit; class QDialogButtonBox; +class QCheckBox; class RegistDialog : public QDialog { @@ -38,6 +39,7 @@ class RegistDialog : public QDialog Settings *settings; QLineEdit *host_edit; + QCheckBox *broadcast_check_box; QLineEdit *psn_id_edit; QLineEdit *pin_edit; QDialogButtonBox *button_box; diff --git a/gui/src/registdialog.cpp b/gui/src/registdialog.cpp index 1d069cc..88c3ad6 100644 --- a/gui/src/registdialog.cpp +++ b/gui/src/registdialog.cpp @@ -26,6 +26,7 @@ #include #include #include +#include Q_DECLARE_METATYPE(ChiakiLogLevel) @@ -52,6 +53,10 @@ RegistDialog::RegistDialog(Settings *settings, const QString &host, QWidget *par else host_edit->setText(host); + broadcast_check_box = new QCheckBox(this); + form_layout->addRow(tr("Broadcast:"), broadcast_check_box); + broadcast_check_box->setChecked(host.isEmpty()); + psn_id_edit = new QLineEdit(this); form_layout->addRow(tr("PSN ID (username):"), psn_id_edit); @@ -90,6 +95,7 @@ void RegistDialog::accept() QByteArray host = host_edit->text().trimmed().toUtf8(); info.psn_id = psn_id.data(); info.host = host.data(); + info.broadcast = broadcast_check_box->isChecked(); info.pin = (uint32_t)pin_edit->text().toULong(); RegistExecuteDialog execute_dialog(settings, info, this); diff --git a/lib/include/chiaki/regist.h b/lib/include/chiaki/regist.h index 5351625..451ac13 100644 --- a/lib/include/chiaki/regist.h +++ b/lib/include/chiaki/regist.h @@ -32,6 +32,7 @@ extern "C" { typedef struct chiaki_regist_info_t { char *host; + bool broadcast; char *psn_id; uint32_t pin; } ChiakiRegistInfo; @@ -50,7 +51,6 @@ typedef struct chiaki_registered_host_t } ChiakiRegisteredHost; typedef enum chiaki_regist_event_type_t { - CHIAKI_REGIST_EVENT_TYPE_CONNECTED, CHIAKI_REGIST_EVENT_TYPE_FINISHED_CANCELED, CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED, CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS diff --git a/lib/src/discovery.c b/lib/src/discovery.c index 0f84faf..3431220 100644 --- a/lib/src/discovery.c +++ b/lib/src/discovery.c @@ -15,6 +15,8 @@ * along with Chiaki. If not, see . */ +#include "utils.h" + #include #include #include @@ -61,21 +63,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_srch_response_parse(ChiakiDiscove memset(response, 0, sizeof(*response)); - void *addr_src; - switch(addr->sa_family) - { - case AF_INET: - addr_src = &((struct sockaddr_in *)addr)->sin_addr; - break; - case AF_INET6: - addr_src = &((struct sockaddr_in6 *)addr)->sin6_addr; - break; - default: - addr_src = NULL; - break; - } - if(addr_src) - response->host_addr = inet_ntop(addr->sa_family, addr_src, addr_buf, addr_buf_size); + response->host_addr = sockaddr_str(addr, addr_buf, addr_buf_size); switch(http_response.code) { diff --git a/lib/src/regist.c b/lib/src/regist.c index 09495d4..2c160bb 100644 --- a/lib/src/regist.c +++ b/lib/src/regist.c @@ -36,8 +36,9 @@ #define REGIST_REPONSE_TIMEOUT_MS 3000 static void *regist_thread_func(void *user); -static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addrinfos); -static int regist_connect(ChiakiRegist *regist, struct addrinfo *addrinfos, int protocol); +static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addrinfos, struct sockaddr *recv_addr, socklen_t *recv_addr_size); +static int regist_search_connect(ChiakiRegist *regist, struct addrinfo *addrinfos, struct sockaddr *send_addr, socklen_t *send_addr_len); +static int regist_request_connect(ChiakiRegist *regist, const struct sockaddr *addr, size_t addr_len); static ChiakiErrorCode regist_recv_response(ChiakiRegist *regist, ChiakiRegisteredHost *host, int sock, ChiakiRPCrypt *rpcrypt); static ChiakiErrorCode regist_parse_response_payload(ChiakiRegist *regist, ChiakiRegisteredHost *host, char *buf, size_t buf_size); @@ -163,7 +164,10 @@ static void *regist_thread_func(void *user) goto fail; } - err = regist_search(regist, addrinfos); // TODO: get addr from response + struct sockaddr recv_addr = {}; + socklen_t recv_addr_size; + recv_addr_size = sizeof(recv_addr); + err = regist_search(regist, addrinfos, &recv_addr, &recv_addr_size); if(err != CHIAKI_ERR_SUCCESS) { if(err == CHIAKI_ERR_CANCELED) @@ -180,7 +184,7 @@ static void *regist_thread_func(void *user) goto fail_addrinfos; } - int sock = regist_connect(regist, addrinfos, IPPROTO_TCP); + int sock = regist_request_connect(regist, &recv_addr, recv_addr_size); if(sock < 0) { CHIAKI_LOGE(regist->log, "Regist eventually failed to connect for request"); @@ -242,10 +246,12 @@ fail: return NULL; } -static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addrinfos) +static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addrinfos, struct sockaddr *recv_addr, socklen_t *recv_addr_size) { CHIAKI_LOGI(regist->log, "Regist starting search"); - int sock = regist_connect(regist, addrinfos, IPPROTO_UDP); + struct sockaddr send_addr; + socklen_t send_addr_len = sizeof(send_addr); + int sock = regist_search_connect(regist, addrinfos, &send_addr, &send_addr_len); if(sock < 0) { CHIAKI_LOGE(regist->log, "Regist eventually failed to connect for search"); @@ -255,10 +261,11 @@ static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addr ChiakiErrorCode err = CHIAKI_ERR_SUCCESS; CHIAKI_LOGI(regist->log, "Regist sending search packet"); - int r = send(sock, "SRC2", 4, 0); + int r = sendto(sock, "SRC2", 4, 0, &send_addr, send_addr_len); if(r < 0) { CHIAKI_LOGE(regist->log, "Regist failed to send search: %s", strerror(errno)); + err = CHIAKI_ERR_NETWORK; goto done; } @@ -278,10 +285,7 @@ static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addr } uint8_t buf[0x100]; - struct sockaddr recv_addr; - socklen_t recv_addr_size; - recv_addr_size = sizeof(recv_addr); - ssize_t n = recvfrom(sock, buf, sizeof(buf) - 1, 0, &recv_addr, &recv_addr_size); + ssize_t n = recvfrom(sock, buf, sizeof(buf) - 1, 0, recv_addr, recv_addr_size); if(n <= 0) { if(n < 0) @@ -297,7 +301,9 @@ static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addr if(n >= 4 && memcmp(buf, "RES2", 4) == 0) { - CHIAKI_LOGI(regist->log, "Regist received search response"); // TODO: print from + char addr[64]; + const char *addr_str = sockaddr_str(recv_addr, addr, sizeof(addr)); + CHIAKI_LOGI(regist->log, "Regist received search response from %s", addr_str ? addr_str : ""); break; } } @@ -307,42 +313,82 @@ done: return err; } -static int regist_connect(ChiakiRegist *regist, struct addrinfo *addrinfos, int protocol) +static int regist_search_connect(ChiakiRegist *regist, struct addrinfo *addrinfos, struct sockaddr *send_addr, socklen_t *send_addr_len) { int sock = -1; for(struct addrinfo *ai=addrinfos; ai; ai=ai->ai_next) { - if(ai->ai_protocol != protocol) + if(ai->ai_protocol != IPPROTO_UDP) continue; if(ai->ai_addr->sa_family != AF_INET) // TODO: support IPv6 continue; - struct sockaddr *sa = malloc(ai->ai_addrlen); - if(!sa) + if(ai->ai_addrlen > *send_addr_len) continue; - memcpy(sa, ai->ai_addr, ai->ai_addrlen); + memcpy(send_addr, ai->ai_addr, ai->ai_addrlen); + *send_addr_len = ai->ai_addrlen; - set_port(sa, htons(REGIST_PORT)); + set_port(send_addr, htons(REGIST_PORT)); sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if(sock < 0) - { - free(sa); continue; - } - int r = connect(sock, sa, ai->ai_addrlen); - if(r < 0) + + if(regist->info.broadcast) { - int errsv = errno; - CHIAKI_LOGE(regist->log, "Regist connect failed: %s", strerror(errsv)); - close(sock); - sock = -1; - free(sa); - continue; + const int broadcast = 1; + int r = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + if(r < 0) + { + CHIAKI_LOGE(regist->log, "Regist failed to setsockopt SO_BROADCAST"); + goto connect_fail; + } + + in_addr_t ip = ((struct sockaddr_in *)send_addr)->sin_addr.s_addr; + ((struct sockaddr_in *)send_addr)->sin_addr.s_addr = INADDR_ANY; + r = bind(sock, send_addr, *send_addr_len); + ((struct sockaddr_in *)send_addr)->sin_addr.s_addr = ip; + if(r < 0) + { + CHIAKI_LOGE(regist->log, "Regist failed to bind socket"); + goto connect_fail; + } + } + else + { + int r = connect(sock, send_addr, *send_addr_len); + if(r < 0) + { + int errsv = errno; + CHIAKI_LOGE(regist->log, "Regist connect failed: %s", strerror(errsv)); + goto connect_fail; + } } - free(sa); break; + +connect_fail: + close(sock); + sock = -1; + } + + return sock; +} + +static int regist_request_connect(ChiakiRegist *regist, const struct sockaddr *addr, size_t addr_len) +{ + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(sock < 0) + { + return -1; + } + + int r = connect(sock, addr, addr_len); + if(r < 0) + { + int errsv = errno; + CHIAKI_LOGE(regist->log, "Regist connect failed: %s", strerror(errsv)); + close(sock); } return sock; diff --git a/lib/src/utils.h b/lib/src/utils.h index 1fa98b2..e4393a8 100644 --- a/lib/src/utils.h +++ b/lib/src/utils.h @@ -20,6 +20,7 @@ #include #include +#include static inline ChiakiErrorCode set_port(struct sockaddr *sa, in_port_t port) { @@ -32,6 +33,26 @@ static inline ChiakiErrorCode set_port(struct sockaddr *sa, in_port_t port) return CHIAKI_ERR_SUCCESS; } +static inline const char *sockaddr_str(struct sockaddr *addr, char *addr_buf, size_t addr_buf_size) +{ + void *addr_src; + switch(addr->sa_family) + { + case AF_INET: + addr_src = &((struct sockaddr_in *)addr)->sin_addr; + break; + case AF_INET6: + addr_src = &((struct sockaddr_in6 *)addr)->sin6_addr; + break; + default: + addr_src = NULL; + break; + } + if(addr_src) + return inet_ntop(addr->sa_family, addr_src, addr_buf, addr_buf_size); + return NULL; +} + static inline void xor_bytes(uint8_t *dst, uint8_t *src, size_t sz) { while(sz > 0)