diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 805508a..09b5d50 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -3,12 +3,15 @@ set(HEADER_FILES include/chiaki/session.h include/chiaki/common.h include/chiaki/thread.h - include/chiaki/base64.h) + include/chiaki/base64.h + include/chiaki/http.h) set(SOURCE_FILES + src/common.c src/session.c src/thread.c - src/base64.c) + src/base64.c + src/http.c) add_library(chiaki-lib ${HEADER_FILES} ${SOURCE_FILES}) set_target_properties(chiaki-lib PROPERTIES OUTPUT_NAME chiaki) diff --git a/lib/include/chiaki/common.h b/lib/include/chiaki/common.h index 78e9a0c..f725c69 100644 --- a/lib/include/chiaki/common.h +++ b/lib/include/chiaki/common.h @@ -24,6 +24,20 @@ extern "C" { #define CHIAKI_EXPORT + +typedef enum +{ + CHIAKI_ERR_SUCCESS = 0, + CHIAKI_ERR_PARSE_ADDR = 1, + CHIAKI_ERR_THREAD = 2, + CHIAKI_ERR_MEMORY = 3, + CHIAKI_ERR_NETWORK = 4, + CHIAKI_ERR_INVALID_DATA = 5 +} ChiakiErrorCode; + +CHIAKI_EXPORT const char *chiaki_error_string(ChiakiErrorCode code); + + #ifdef __cplusplus } #endif diff --git a/lib/include/chiaki/http.h b/lib/include/chiaki/http.h new file mode 100644 index 0000000..f694921 --- /dev/null +++ b/lib/include/chiaki/http.h @@ -0,0 +1,55 @@ +/* + * 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 . + */ + +#ifndef CHIAKI_HTTP_H +#define CHIAKI_HTTP_H + +#include "common.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct chiaki_http_header_t +{ + const char *key; + const char *value; + struct chiaki_http_header_t *next; +} ChiakiHttpHeader; + +typedef struct chiaki_http_response_t +{ + int code; + ChiakiHttpHeader *headers; +} ChiakiHttpResponse; + +CHIAKI_EXPORT void chiaki_http_header_free(ChiakiHttpHeader *header); +CHIAKI_EXPORT ChiakiErrorCode chiaki_http_header_parse(ChiakiHttpHeader **header, char *buf, size_t buf_size); + +CHIAKI_EXPORT void chiaki_http_response_fini(ChiakiHttpResponse *response); +CHIAKI_EXPORT ChiakiErrorCode chiaki_http_response_parse(ChiakiHttpResponse *response, char *buf, size_t buf_size); + +CHIAKI_EXPORT ChiakiErrorCode chiaki_recv_http_header(int sock, char *buf, size_t buf_size, size_t *header_size, size_t *received_size); + + +#ifdef __cplusplus +} +#endif + +#endif // CHIAKI_HTTP_H diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h index f80edc3..1489053 100644 --- a/lib/include/chiaki/session.h +++ b/lib/include/chiaki/session.h @@ -22,6 +22,7 @@ #include "thread.h" #include +#include #ifdef __cplusplus extern "C" { @@ -40,7 +41,8 @@ typedef struct chiaki_session_t { struct { - char *host; + struct addrinfo *host_addrinfos; + struct addrinfo *host_addrinfo_selected; char *regist_key; char *ostype; char auth[0x10]; @@ -50,10 +52,10 @@ typedef struct chiaki_session_t ChiakiThread session_thread; } ChiakiSession; -CHIAKI_EXPORT void chiaki_session_init(ChiakiSession *session, ChiakiConnectInfo *connect_info); +CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, ChiakiConnectInfo *connect_info); CHIAKI_EXPORT void chiaki_session_fini(ChiakiSession *session); -CHIAKI_EXPORT bool chiaki_session_start(ChiakiSession *session); -CHIAKI_EXPORT void chiaki_session_join(ChiakiSession *session); +CHIAKI_EXPORT ChiakiErrorCode chiaki_session_start(ChiakiSession *session); +CHIAKI_EXPORT ChiakiErrorCode chiaki_session_join(ChiakiSession *session); #ifdef __cplusplus } diff --git a/lib/include/chiaki/thread.h b/lib/include/chiaki/thread.h index 910973e..3ba8bb3 100644 --- a/lib/include/chiaki/thread.h +++ b/lib/include/chiaki/thread.h @@ -20,8 +20,6 @@ #include "common.h" -#include - #ifdef __cplusplus extern "C" { #endif @@ -35,8 +33,8 @@ typedef struct chiaki_thread_t typedef void *(*ChiakiThreadFunc)(void *); -CHIAKI_EXPORT bool chiaki_thread_create(ChiakiThread *thread, ChiakiThreadFunc func, void *arg); -CHIAKI_EXPORT bool chiaki_thread_join(ChiakiThread *thread, void **retval); +CHIAKI_EXPORT ChiakiErrorCode chiaki_thread_create(ChiakiThread *thread, ChiakiThreadFunc func, void *arg); +CHIAKI_EXPORT ChiakiErrorCode chiaki_thread_join(ChiakiThread *thread, void **retval); #ifdef __cplusplus } diff --git a/lib/src/common.c b/lib/src/common.c new file mode 100644 index 0000000..42b5a60 --- /dev/null +++ b/lib/src/common.c @@ -0,0 +1,39 @@ +/* + * 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 + +CHIAKI_EXPORT const char *chiaki_error_string(ChiakiErrorCode code) +{ + switch(code) + { + case CHIAKI_ERR_SUCCESS: + return "Success"; + case CHIAKI_ERR_PARSE_ADDR: + return "Failed to parse host address"; + case CHIAKI_ERR_THREAD: + return "Thread error"; + case CHIAKI_ERR_MEMORY: + return "Memory error"; + case CHIAKI_ERR_NETWORK: + return "Network error"; + case CHIAKI_ERR_INVALID_DATA: + return "Invalid data"; + default: + return "Unknown"; + } +} \ No newline at end of file diff --git a/lib/src/http.c b/lib/src/http.c new file mode 100644 index 0000000..4788413 --- /dev/null +++ b/lib/src/http.c @@ -0,0 +1,126 @@ +/* + * 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 + +#include +#include +#include + + +CHIAKI_EXPORT void chiaki_http_header_free(ChiakiHttpHeader *header) +{ + while(header) + { + ChiakiHttpHeader *cur = header; + header = header->next; + free(cur); + } +} + +CHIAKI_EXPORT ChiakiErrorCode chiaki_http_header_parse(ChiakiHttpHeader **header, char *buf, size_t buf_size) +{ + *header = NULL; + return CHIAKI_ERR_SUCCESS; +} + +CHIAKI_EXPORT void chiaki_http_response_fini(ChiakiHttpResponse *response) +{ + if(!response) + return; + chiaki_http_header_free(response->headers); +} + +CHIAKI_EXPORT ChiakiErrorCode chiaki_http_response_parse(ChiakiHttpResponse *response, char *buf, size_t buf_size) +{ + static const char *http_version = "HTTP/1.1 "; + static const size_t http_version_size = 9; + + if(buf_size < http_version_size) + return CHIAKI_ERR_INVALID_DATA; + + if(strncmp(buf, http_version, http_version_size) != 0) + return CHIAKI_ERR_INVALID_DATA; + + buf += http_version_size; + buf_size -= http_version_size; + + char *line_end = memchr(buf, '\r', buf_size); + if(!line_end) + return CHIAKI_ERR_INVALID_DATA; + size_t line_length = (line_end - buf) + 2; + if(buf_size <= line_length || line_end[1] != '\n') + return CHIAKI_ERR_INVALID_DATA; + *line_end = '\0'; + + char *endptr; + response->code = (int)strtol(buf, &endptr, 10); + if(response->code == 0) + return CHIAKI_ERR_INVALID_DATA; + + buf += line_length; + buf_size -= line_length; + + return chiaki_http_header_parse(&response->headers, buf, buf_size); +} + +CHIAKI_EXPORT ChiakiErrorCode chiaki_recv_http_header(int sock, char *buf, size_t buf_size, size_t *header_size, size_t *received_size) +{ + // 0 = "" + // 1 = "\r" + // 2 = "\r\n" + // 3 = "\r\n\r" + // 4 = "\r\n\r\n" (final) + int nl_state = 0; + static const int transitions_r[] = { 1, 1, 3, 1 }; + static const int transitions_n[] = { 0, 2, 0, 4 }; + + *received_size = 0; + while(true) + { + ssize_t received = recv(sock, buf, buf_size, 0); + if(received <= 0) + return CHIAKI_ERR_NETWORK; + + *received_size += received; + for(; received > 0; buf++, received--) + { + switch(*buf) + { + case '\r': + nl_state = transitions_r[nl_state]; + break; + case '\n': + nl_state = transitions_n[nl_state]; + break; + default: + nl_state = 0; + break; + } + if(nl_state == 4) + break; + } + + if(nl_state == 4) + { + *header_size = *received_size - received; + break; + } + } + + return CHIAKI_ERR_SUCCESS; +} \ No newline at end of file diff --git a/lib/src/session.c b/lib/src/session.c index 57662e7..f6556ed 100644 --- a/lib/src/session.c +++ b/lib/src/session.c @@ -16,58 +16,198 @@ */ #include +#include #include #include #include +#include + +#include +#include -static const char session_request[] = - "GET /sce/rp/session HTTP/1.1\r\n" - "Host: 192.168. 1. 8:9295\r\n" - "User-Agent: remoteplay Windows\r\n" - "Connection: close\r\n" - "Content-Length: 0\r\n" - "RP-Registkey: 3131633065363864\r\n" - "Rp-Version: 8.0\r\n" - "\r\n"; +#define SESSION_PORT 9295 + static void *session_thread_func(void *arg); -CHIAKI_EXPORT void chiaki_session_init(ChiakiSession *session, ChiakiConnectInfo *connect_info) +CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, ChiakiConnectInfo *connect_info) { - session->connect_info.host = strdup(connect_info->host); + memset(session, 0, sizeof(ChiakiSession)); + + int r = getaddrinfo(connect_info->host, NULL, NULL, &session->connect_info.host_addrinfos); + if(r != 0) + { + chiaki_session_fini(session); + return CHIAKI_ERR_PARSE_ADDR; + } + session->connect_info.regist_key = strdup(connect_info->regist_key); + if(!session->connect_info.regist_key) + { + chiaki_session_fini(session); + return CHIAKI_ERR_MEMORY; + } + session->connect_info.ostype = strdup(connect_info->ostype); + if(!session->connect_info.regist_key) + { + chiaki_session_fini(session); + return CHIAKI_ERR_MEMORY; + } + memcpy(session->connect_info.auth, connect_info->auth, sizeof(session->connect_info.auth)); memcpy(session->connect_info.morning, connect_info->morning, sizeof(session->connect_info.morning)); + + return CHIAKI_ERR_SUCCESS; } CHIAKI_EXPORT void chiaki_session_fini(ChiakiSession *session) { - free(session->connect_info.host); + if(!session) + return; free(session->connect_info.regist_key); free(session->connect_info.ostype); + freeaddrinfo(session->connect_info.host_addrinfos); } -CHIAKI_EXPORT bool chiaki_session_start(ChiakiSession *session) +CHIAKI_EXPORT ChiakiErrorCode chiaki_session_start(ChiakiSession *session) { - bool r = chiaki_thread_create(&session->session_thread, session_thread_func, session); - if(!r) - return false; - return true; + return chiaki_thread_create(&session->session_thread, session_thread_func, session); } -CHIAKI_EXPORT void chiaki_session_join(ChiakiSession *session) +CHIAKI_EXPORT ChiakiErrorCode chiaki_session_join(ChiakiSession *session) { - chiaki_thread_join(&session->session_thread, NULL); + return chiaki_thread_join(&session->session_thread, NULL); } + + +static ChiakiErrorCode session_thread_request_session(ChiakiSession *session); + static void *session_thread_func(void *arg) { ChiakiSession *session = arg; - printf("Sleepy...\n"); + ChiakiErrorCode err; + + err = session_thread_request_session(session); + if(err != CHIAKI_ERR_SUCCESS) + return NULL; + return NULL; -} \ No newline at end of file +} + + +static ChiakiErrorCode 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) + { + struct sockaddr *sa = malloc(ai->ai_addrlen); + if(!sa) + continue; + memcpy(sa, ai->ai_addr, ai->ai_addrlen); + + if(sa->sa_family == AF_INET) + ((struct sockaddr_in *)sa)->sin_port = htons(SESSION_PORT); + else if(sa->sa_family == AF_INET6) + ((struct sockaddr_in6 *)sa)->sin6_port = htons(SESSION_PORT); + else + { + free(sa); + continue; + } + + int r = getnameinfo(sa, ai->ai_addrlen, host_buf, sizeof(host_buf), NULL, 0, 0); + if(r != 0) + { + free(sa); + continue; + } + + session_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if(session_sock < 0) + continue; + r = connect(session_sock, sa, ai->ai_addrlen); + if(r < 0) + { + close(session_sock); + session_sock = -1; + free(sa); + continue; + } + free(sa); + + session->connect_info.host_addrinfo_selected = ai; + break; + } + + + if(session_sock < 0) + { + printf("Session Connection Failed.\n"); + return CHIAKI_ERR_NETWORK; + } + + 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" + "User-Agent: remoteplay Windows\r\n" + "Connection: close\r\n" + "Content-Length: 0\r\n" + "RP-Registkey: %s\r\n" + "Rp-Version: 8.0\r\n" + "\r\n"; + + char buf[512]; + int request_len = snprintf(buf, sizeof(buf), session_request_fmt, + 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; + } + + printf("sending\n%s\n", buf); + + 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; + } + + size_t header_size; + size_t received_size; + ChiakiErrorCode err = chiaki_recv_http_header(session_sock, buf, sizeof(buf), &header_size, &received_size); + if(err != CHIAKI_ERR_SUCCESS) + { + close(session_sock); + return err; + } + + buf[received_size] = '\0'; + printf("received\n%s\n", buf); + + ChiakiHttpResponse response; + err = chiaki_http_response_parse(&response, buf, header_size); + if(err != CHIAKI_ERR_SUCCESS) + { + close(session_sock); + return err; + } + + close(session_sock); + return CHIAKI_ERR_SUCCESS; +} + diff --git a/lib/src/thread.c b/lib/src/thread.c index 256be43..a9f8873 100644 --- a/lib/src/thread.c +++ b/lib/src/thread.c @@ -20,24 +20,18 @@ #include -CHIAKI_EXPORT bool chiaki_thread_create(ChiakiThread *thread, ChiakiThreadFunc func, void *arg) +CHIAKI_EXPORT ChiakiErrorCode chiaki_thread_create(ChiakiThread *thread, ChiakiThreadFunc func, void *arg) { int r = pthread_create(&thread->thread, NULL, func, arg); if(r != 0) - { - perror("pthread_create"); - return false; - } - return true; + return CHIAKI_ERR_THREAD; + return CHIAKI_ERR_SUCCESS; } -CHIAKI_EXPORT bool chiaki_thread_join(ChiakiThread *thread, void **retval) +CHIAKI_EXPORT ChiakiErrorCode chiaki_thread_join(ChiakiThread *thread, void **retval) { int r = pthread_join(thread->thread, retval); if(r != 0) - { - perror("pthread_join"); - return false; - } - return true; + return CHIAKI_ERR_THREAD; + return CHIAKI_ERR_SUCCESS; } \ No newline at end of file