From 2fa6ad8b212a9024cb4b6d0f7c730d3da99235e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 16 Nov 2018 21:39:18 +0100 Subject: [PATCH] Session Request working --- CMakeLists.txt | 3 +- gui/CMakeLists.txt | 3 + gui/main.c | 4 +- lib/include/chiaki/base64.h | 2 +- lib/include/chiaki/common.h | 3 +- lib/include/chiaki/session.h | 48 ++++++++++++- lib/src/base64.c | 12 ++-- lib/src/http.c | 54 ++++++++++++++ lib/src/session.c | 133 ++++++++++++++++++++++++++++++----- test/http.c | 17 +++++ test/main.c | 17 ++++- 11 files changed, 263 insertions(+), 33 deletions(-) create mode 100644 gui/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dc8837..3040d6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,9 @@ project(chiaki) option(CHIAKI_ENABLE_TESTS "Enable tests for Chiaki" ON) add_subdirectory(lib) +add_subdirectory(gui) if(CHIAKI_ENABLE_TESTS) enable_testing() add_subdirectory(test) -endif() \ No newline at end of file +endif() diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt new file mode 100644 index 0000000..49efc4a --- /dev/null +++ b/gui/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(chiaki main.c) +target_link_libraries(chiaki chiaki-lib) \ No newline at end of file diff --git a/gui/main.c b/gui/main.c index a9dd25b..cc615e9 100644 --- a/gui/main.c +++ b/gui/main.c @@ -25,8 +25,8 @@ int main(int argc, const char *argv[]) memset(connect_info.auth + auth_len, 0, sizeof(connect_info.auth) - auth_len); size_t morning_size = sizeof(connect_info.morning); - bool r = chiaki_base64_decode(argv[5], strlen(argv[5]), connect_info.morning, &morning_size); - if(!r || morning_size != sizeof(connect_info.morning)) + ChiakiErrorCode err = chiaki_base64_decode(argv[5], strlen(argv[5]), connect_info.morning, &morning_size); + if(err != CHIAKI_ERR_SUCCESS || morning_size != sizeof(connect_info.morning)) { printf("morning invalid.\n"); return 1; diff --git a/lib/include/chiaki/base64.h b/lib/include/chiaki/base64.h index 8b0933e..b6bc9b1 100644 --- a/lib/include/chiaki/base64.h +++ b/lib/include/chiaki/base64.h @@ -28,7 +28,7 @@ extern "C" { #endif -CHIAKI_EXPORT bool chiaki_base64_decode(const char *in, size_t in_size, uint8_t *out, size_t *out_size); +CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_decode(const char *in, size_t in_size, uint8_t *out, size_t *out_size); #ifdef __cplusplus } diff --git a/lib/include/chiaki/common.h b/lib/include/chiaki/common.h index f725c69..8827dcc 100644 --- a/lib/include/chiaki/common.h +++ b/lib/include/chiaki/common.h @@ -32,7 +32,8 @@ typedef enum CHIAKI_ERR_THREAD = 2, CHIAKI_ERR_MEMORY = 3, CHIAKI_ERR_NETWORK = 4, - CHIAKI_ERR_INVALID_DATA = 5 + CHIAKI_ERR_INVALID_DATA = 5, + CHIAKI_ERR_BUF_TOO_SMALL = 6 } ChiakiErrorCode; CHIAKI_EXPORT const char *chiaki_error_string(ChiakiErrorCode code); diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h index 1489053..da8ae25 100644 --- a/lib/include/chiaki/session.h +++ b/lib/include/chiaki/session.h @@ -37,6 +37,37 @@ typedef struct chiaki_connect_info_t uint8_t morning[0x10]; } ChiakiConnectInfo; + +typedef enum { + CHIAKI_QUIT_REASON_NONE, + CHIAKI_QUIT_REASON_SESSION_REQUEST_CONNECTION_REFUSED, + CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN, + CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_IN_USE, + CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_CRASH +} ChiakiQuitReason; + +typedef struct chiaki_quit_event_t +{ + ChiakiQuitReason reason; +} ChiakiQuitEvent; + + +typedef enum { CHIAKI_EVENT_QUIT } ChiakiEventType; + +typedef struct chiaki_event_t +{ + ChiakiEventType type; + union + { + ChiakiQuitEvent quit; + }; +} ChiakiEvent; + +typedef void (*ChiakiEventCallback)(ChiakiEvent *event, void *user); + + +#define CHIAKI_KEY_BYTES 0x10 + typedef struct chiaki_session_t { struct @@ -45,10 +76,17 @@ typedef struct chiaki_session_t struct addrinfo *host_addrinfo_selected; char *regist_key; char *ostype; - char auth[0x10]; - uint8_t morning[0x10]; + char auth[CHIAKI_KEY_BYTES]; + uint8_t morning[CHIAKI_KEY_BYTES]; } connect_info; + uint8_t nonce[CHIAKI_KEY_BYTES]; + + ChiakiQuitReason quit_reason; + + ChiakiEventCallback event_cb; + void *event_cb_user; + ChiakiThread session_thread; } ChiakiSession; @@ -57,6 +95,12 @@ CHIAKI_EXPORT void chiaki_session_fini(ChiakiSession *session); CHIAKI_EXPORT ChiakiErrorCode chiaki_session_start(ChiakiSession *session); CHIAKI_EXPORT ChiakiErrorCode chiaki_session_join(ChiakiSession *session); +static inline void chiaki_session_set_event_cb(ChiakiSession *session, ChiakiEventCallback cb, void *user) +{ + session->event_cb = cb; + session->event_cb_user = user; +} + #ifdef __cplusplus } #endif diff --git a/lib/src/base64.c b/lib/src/base64.c index 26187a7..22dc040 100644 --- a/lib/src/base64.c +++ b/lib/src/base64.c @@ -40,7 +40,7 @@ static const unsigned char d[] = { 66,66,66,66,66,66 }; -CHIAKI_EXPORT bool chiaki_base64_decode(const char *in, size_t in_size, uint8_t *out, size_t *out_size) +CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_decode(const char *in, size_t in_size, uint8_t *out, size_t *out_size) { const char *end = in + in_size; char iter = 0; @@ -56,7 +56,7 @@ CHIAKI_EXPORT bool chiaki_base64_decode(const char *in, size_t in_size, uint8_t case WHITESPACE: continue; // skip whitespace case INVALID: - return false; // invalid input + return CHIAKI_ERR_INVALID_DATA; // invalid input case EQUALS: // pad character, end of data in = end; continue; @@ -67,7 +67,7 @@ CHIAKI_EXPORT bool chiaki_base64_decode(const char *in, size_t in_size, uint8_t if(iter == 4) { if((len += 3) > *out_size) - return false; // buffer overflow + return CHIAKI_ERR_BUF_TOO_SMALL; *(out++) = (unsigned char)((buf >> 16) & 0xff); *(out++) = (unsigned char)((buf >> 8) & 0xff); *(out++) = (unsigned char)(buf & 0xff); @@ -79,17 +79,17 @@ CHIAKI_EXPORT bool chiaki_base64_decode(const char *in, size_t in_size, uint8_t if(iter == 3) { if((len += 2) > *out_size) - return false; // buffer overflow + return CHIAKI_ERR_BUF_TOO_SMALL; *(out++) = (unsigned char)((buf >> 10) & 0xff); *(out++) = (unsigned char)((buf >> 2) & 0xff); } else if(iter == 2) { if(++len > *out_size) - return 1; // buffer overflow + return CHIAKI_ERR_BUF_TOO_SMALL; *(out++) = (unsigned char)((buf >> 4) & 0xff); } *out_size = len; - return true; + return CHIAKI_ERR_SUCCESS; } \ No newline at end of file diff --git a/lib/src/http.c b/lib/src/http.c index 4788413..42320bc 100644 --- a/lib/src/http.c +++ b/lib/src/http.c @@ -35,7 +35,61 @@ CHIAKI_EXPORT void chiaki_http_header_free(ChiakiHttpHeader *header) CHIAKI_EXPORT ChiakiErrorCode chiaki_http_header_parse(ChiakiHttpHeader **header, char *buf, size_t buf_size) { *header = NULL; +#define FAIL(reason) do { chiaki_http_header_free(*header); return (reason); } while(0); + char *key_ptr = buf; + char *value_ptr = NULL; + + for(char *end = buf + buf_size; bufkey = key_ptr; + entry->value = value_ptr; + entry->next = *header; + *header = entry; + + key_ptr = buf + 1; + value_ptr = NULL; + } + } + } return CHIAKI_ERR_SUCCESS; +#undef FAIL } CHIAKI_EXPORT void chiaki_http_response_fini(ChiakiHttpResponse *response) diff --git a/lib/src/session.c b/lib/src/session.c index f6556ed..732286e 100644 --- a/lib/src/session.c +++ b/lib/src/session.c @@ -17,18 +17,23 @@ #include #include +#include #include #include #include #include +#include +#include #include #include -#define SESSION_PORT 9295 +#define SESSION_PORT 9295 +#define RP_APPLICATION_REASON_IN_USE 0x80108b10 +#define RP_APPLICATION_REASON_CRASH 0x80108b15 static void *session_thread_func(void *arg); @@ -38,6 +43,8 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, Chiaki { memset(session, 0, sizeof(ChiakiSession)); + session->quit_reason = CHIAKI_QUIT_REASON_NONE; + int r = getaddrinfo(connect_info->host, NULL, NULL, &session->connect_info.host_addrinfos); if(r != 0) { @@ -84,29 +91,81 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_join(ChiakiSession *session) return chiaki_thread_join(&session->session_thread, NULL); } +static void session_send_event(ChiakiSession *session, ChiakiEvent *event) +{ + if(!session->event_cb) + return; + session->event_cb(event, session->event_cb_user); +} -static ChiakiErrorCode session_thread_request_session(ChiakiSession *session); +static bool session_thread_request_session(ChiakiSession *session); static void *session_thread_func(void *arg) { ChiakiSession *session = arg; - ChiakiErrorCode err; + bool success; - err = session_thread_request_session(session); - if(err != CHIAKI_ERR_SUCCESS) - return NULL; + success = session_thread_request_session(session); + if(!success) + goto quit; + printf("Connected!\n"); + + ChiakiEvent quit_event; +quit: + quit_event.type = CHIAKI_EVENT_QUIT; + quit_event.quit.reason = session->quit_reason; + session_send_event(session, &quit_event); return NULL; } -static ChiakiErrorCode session_thread_request_session(ChiakiSession *session) + + +typedef struct session_response_t { + uint32_t error_code; + const char *nonce; + const char *rp_version; + bool success; +} SessionResponse; + +static void parse_session_response(SessionResponse *response, ChiakiHttpResponse *http_response) +{ + memset(response, 0, sizeof(SessionResponse)); + + if(http_response->code == 200) + { + for(ChiakiHttpHeader *header=http_response->headers; header; header=header->next) + { + if(strcmp(header->key, "RP-Nonce") == 0) + response->nonce = header->value; + else if(strcmp(header->key, "RP-Version") == 0) + response->rp_version = header->value; + } + response->success = response->nonce != NULL; + } + else + { + for(ChiakiHttpHeader *header=http_response->headers; header; header=header->next) + { + if(strcmp(header->key, "RP-Application-Reason") == 0) + response->error_code = (uint32_t)strtol(header->value, NULL, 0x10); + } + response->success = false; + } +} + + +static bool session_thread_request_session(ChiakiSession *session) { int session_sock = -1; char host_buf[128]; for(struct addrinfo *ai=session->connect_info.host_addrinfos; ai; ai=ai->ai_next) { + if(ai->ai_protocol != IPPROTO_TCP) + continue; + struct sockaddr *sa = malloc(ai->ai_addrlen); if(!sa) continue; @@ -135,6 +194,10 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session) r = connect(session_sock, sa, ai->ai_addrlen); if(r < 0) { + if(errno == ECONNREFUSED) + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_CONNECTION_REFUSED; + else + session->quit_reason = CHIAKI_QUIT_REASON_NONE; close(session_sock); session_sock = -1; free(sa); @@ -150,12 +213,13 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session) if(session_sock < 0) { printf("Session Connection Failed.\n"); - return CHIAKI_ERR_NETWORK; + if(session->quit_reason == CHIAKI_QUIT_REASON_NONE) + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; + return false; } printf("Connected to %s:%u\n", host_buf, SESSION_PORT); - static const char session_request_fmt[] = "GET /sce/rp/session HTTP/1.1\r\n" "Host: %s:%d\r\n" @@ -171,9 +235,9 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session) host_buf, SESSION_PORT, session->connect_info.regist_key); if(request_len < 0 || request_len >= sizeof(buf)) { - printf("Session Request Building Failed.\n"); close(session_sock); - return CHIAKI_ERR_MEMORY; + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; + return false; } printf("sending\n%s\n", buf); @@ -181,10 +245,9 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session) ssize_t sent = send(session_sock, buf, (size_t)request_len, 0); if(sent < 0) { - printf("Session Request Send Failed.\n"); - perror("send"); close(session_sock); - return CHIAKI_ERR_NETWORK; + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; + return false; } size_t header_size; @@ -193,21 +256,53 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session) if(err != CHIAKI_ERR_SUCCESS) { close(session_sock); - return err; + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; + return false; } buf[received_size] = '\0'; printf("received\n%s\n", buf); - ChiakiHttpResponse response; - err = chiaki_http_response_parse(&response, buf, header_size); + ChiakiHttpResponse http_response; + err = chiaki_http_response_parse(&http_response, buf, header_size); if(err != CHIAKI_ERR_SUCCESS) { close(session_sock); - return err; + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; + return false; } + SessionResponse response; + parse_session_response(&response, &http_response); + + if(response.success) + { + size_t nonce_len = CHIAKI_KEY_BYTES; + err = chiaki_base64_decode(response.nonce, strlen(response.nonce), session->nonce, &nonce_len); + if(err != CHIAKI_ERR_SUCCESS || nonce_len != CHIAKI_KEY_BYTES) + { + response.success = false; + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; + } + } + else + { + switch(response.error_code) + { + case RP_APPLICATION_REASON_IN_USE: + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_IN_USE; + break; + case RP_APPLICATION_REASON_CRASH: + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_CRASH; + break; + default: + session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; + break; + } + } + + chiaki_http_response_fini(&http_response); close(session_sock); - return CHIAKI_ERR_SUCCESS; + return response.success; } diff --git a/test/http.c b/test/http.c index 99dc984..ee0eaf4 100644 --- a/test/http.c +++ b/test/http.c @@ -18,10 +18,12 @@ #include #include +#include static const char *response = "HTTP/1.1 200 OK\r\n" "Content-type: text/html, text, plain\r\n" + "Ultimate Ability: Gamer\r\n" "\r\n"; static void *test_http_response_parse_setup(const MunitParameter params[], void *user) @@ -41,6 +43,21 @@ static MunitResult test_http_response_parse(const MunitParameter params[], void ChiakiErrorCode err = chiaki_http_response_parse(&parsed_response, buf, strlen(buf)); munit_assert_int(err, ==, CHIAKI_ERR_SUCCESS); munit_assert_int(parsed_response.code, ==, 200); + + ChiakiHttpHeader *header = parsed_response.headers; + munit_assert_ptr_not_null(header); + munit_assert_string_equal(header->key, "Ultimate Ability"); + munit_assert_string_equal(header->value, "Gamer"); + + header = header->next; + munit_assert_ptr_not_null(header); + munit_assert_string_equal(header->key, "Content-type"); + munit_assert_string_equal(header->value, "text/html, text, plain"); + + header = header->next; + munit_assert_ptr_null(header); + + chiaki_http_response_fini(&parsed_response); return MUNIT_OK; } diff --git a/test/main.c b/test/main.c index 2d363a2..9d1ce1e 100644 --- a/test/main.c +++ b/test/main.c @@ -1,4 +1,19 @@ - +/* + * This file is part of Chiaki. + * + * Chiaki is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chiaki is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chiaki. If not, see . + */ #include