Session HTTP Request

This commit is contained in:
Florian Märkl 2018-11-15 22:39:10 +01:00
commit 27286817db
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
9 changed files with 414 additions and 43 deletions

View file

@ -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)

View file

@ -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

55
lib/include/chiaki/http.h Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef CHIAKI_HTTP_H
#define CHIAKI_HTTP_H
#include "common.h"
#include <stdlib.h>
#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

View file

@ -22,6 +22,7 @@
#include "thread.h"
#include <stdint.h>
#include <netdb.h>
#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
}

View file

@ -20,8 +20,6 @@
#include "common.h"
#include <stdbool.h>
#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
}

39
lib/src/common.c Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <chiaki/common.h>
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";
}
}

126
lib/src/http.c Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <chiaki/http.h>
#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
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;
}

View file

@ -16,58 +16,198 @@
*/
#include <chiaki/session.h>
#include <chiaki/http.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
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;
}
}
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;
}

View file

@ -20,24 +20,18 @@
#include <stdio.h>
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;
}