meow
This commit is contained in:
commit
7451820765
30 changed files with 2026 additions and 0 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
* text=auto
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
bin/
|
||||||
|
*.o
|
||||||
|
*.cfg
|
||||||
|
*.dat
|
48
Makefile
Normal file
48
Makefile
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
TARGET ?= satori
|
||||||
|
SRCDIR := ./src
|
||||||
|
INCDIR := ./include
|
||||||
|
BINDIR := ./bin
|
||||||
|
|
||||||
|
DATE = $(shell date +%Y%m%d)
|
||||||
|
|
||||||
|
C_SRC := $(wildcard $(SRCDIR)/*.c) $(wildcard $(SRCDIR)/**/*.c)
|
||||||
|
CXX_SRC := $(wildcard $(SRCDIR)/*.cxx) $(wildcard $(SRCDIR)/**/*.cxx)
|
||||||
|
|
||||||
|
OBJ := $(C_SRC:.c=.o) $(CXX_SRC:.cxx=.o)
|
||||||
|
OUT := $(BINDIR)/$(TARGET)
|
||||||
|
|
||||||
|
LIBNAMES := libcurl openssl lua54 json-c $(LIBNAMES)
|
||||||
|
|
||||||
|
CFLAGS := -Wall -Wextra -g -O2 --std=c11 -DSATORI_VERSION=\"$(DATE)\" -D_POSIX_C_SOURCE=200112L $(CFLAGS)
|
||||||
|
CXXFLAGS := $(CXXFLAGS)
|
||||||
|
CPPFLAGS := -I$(INCDIR) $(shell pkg-config --cflags $(LIBNAMES)) $(CPPFLAGS)
|
||||||
|
LDFLAGS := $(LDFLAGS)
|
||||||
|
LDLIBS := $(shell pkg-config --libs $(LIBNAMES)) $(LDLIBS)
|
||||||
|
|
||||||
|
all: $(OUT)
|
||||||
|
|
||||||
|
$(OUT): $(OBJ)
|
||||||
|
mkdir -p $(BINDIR)
|
||||||
|
$(CC) $(LDFLAGS) $(CPPFLAGS) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
.cxx.o:
|
||||||
|
@echo "CXX> " $@
|
||||||
|
$(CC) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
@echo "C> " $@
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ) $(OUT)
|
||||||
|
|
||||||
|
rebuild: clean all
|
||||||
|
|
||||||
|
run: all
|
||||||
|
$(OUT)
|
||||||
|
|
||||||
|
gdb: all
|
||||||
|
gdb $(OUT)
|
||||||
|
|
||||||
|
.PHONY: all clean rebuild
|
||||||
|
.SUFFIXES: .c .cxx
|
40
include/buffer.h
Normal file
40
include/buffer.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef H_SATORI_BUFFER
|
||||||
|
#define H_SATORI_BUFFER
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define SAT_BUFFER_PIECE_SIZE (1024)
|
||||||
|
#define SAT_BUFFER_PIECE_MAX (SAT_BUFFER_PIECE_SIZE - 1)
|
||||||
|
|
||||||
|
typedef struct _sat_buffer_piece {
|
||||||
|
struct _sat_buffer_piece *next;
|
||||||
|
char data[SAT_BUFFER_PIECE_SIZE];
|
||||||
|
} sat_buffer_piece, *sat_buffer_piece_ptr;
|
||||||
|
|
||||||
|
typedef struct _sat_buffer {
|
||||||
|
size_t available;
|
||||||
|
sat_buffer_piece_ptr start;
|
||||||
|
|
||||||
|
size_t rPos;
|
||||||
|
sat_buffer_piece_ptr rCurrent;
|
||||||
|
|
||||||
|
size_t wPos;
|
||||||
|
sat_buffer_piece_ptr wCurrent;
|
||||||
|
} sat_buffer, *sat_buffer_ptr;
|
||||||
|
|
||||||
|
sat_buffer_ptr sat_buffer_alloc(void);
|
||||||
|
void sat_buffer_free(sat_buffer_ptr buffer);
|
||||||
|
|
||||||
|
bool sat_buffer_pending(sat_buffer_ptr buffer);
|
||||||
|
size_t sat_buffer_available(sat_buffer_ptr buffer);
|
||||||
|
void sat_buffer_tidy(sat_buffer_ptr buffer);
|
||||||
|
|
||||||
|
int sat_buffer_write(sat_buffer_ptr buffer, char *source, size_t count);
|
||||||
|
void sat_buffer_putc(sat_buffer_ptr buffer, char value);
|
||||||
|
|
||||||
|
int sat_buffer_read(sat_buffer_ptr buffer, char *target, size_t length);
|
||||||
|
char sat_buffer_getc(sat_buffer_ptr buffer);
|
||||||
|
|
||||||
|
#endif // H_SATORI_BUFFER
|
56
include/config.h
Normal file
56
include/config.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef H_SATORI_CONFIG
|
||||||
|
#define H_SATORI_CONFIG
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <threads.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define SAT_CONFIG_TYPE_STREAM (1)
|
||||||
|
#define SAT_CONFIG_TYPE_SCOPED (2)
|
||||||
|
|
||||||
|
typedef struct _sat_config {
|
||||||
|
int type;
|
||||||
|
void *info;
|
||||||
|
struct _sat_config *(*scopeTo)(struct _sat_config *ctx, char *prefix);
|
||||||
|
char *(*readValue)(struct _sat_config *ctx, char *name, char *fallback);
|
||||||
|
} sat_config, *sat_config_ptr;
|
||||||
|
|
||||||
|
typedef struct _sat_config_stream {
|
||||||
|
FILE *stream;
|
||||||
|
bool ownsStream;
|
||||||
|
long offset;
|
||||||
|
mtx_t *lock;
|
||||||
|
} sat_config_stream, *sat_config_stream_ptr;
|
||||||
|
|
||||||
|
typedef struct _sat_config_scoped {
|
||||||
|
sat_config_ptr parent;
|
||||||
|
char *prefix;
|
||||||
|
} sat_config_scoped, *sat_config_scoped_ptr;
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_alloc(int type);
|
||||||
|
sat_config_ptr sat_config_alloc_stream(void);
|
||||||
|
sat_config_ptr sat_config_alloc_scoped(void);
|
||||||
|
|
||||||
|
void sat_config_free(sat_config_ptr ctx);
|
||||||
|
void sat_config_free_stream(sat_config_ptr ctx);
|
||||||
|
void sat_config_free_scoped(sat_config_ptr ctx);
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_scope_to(sat_config_ptr ctx, char *prefix);
|
||||||
|
|
||||||
|
char* sat_config_read_value(sat_config_ptr ctx, char *name, char *fallback);
|
||||||
|
bool sat_config_read_bool(sat_config_ptr ctx, char *name, bool fallback);
|
||||||
|
uint64_t sat_config_read_u64(sat_config_ptr ctx, char *name, uint64_t fallback);
|
||||||
|
|
||||||
|
int sat_config_stream_open(sat_config_ptr ctx, FILE *stream, bool ownsStream);
|
||||||
|
int sat_config_stream_open_file(sat_config_ptr ctx, char *path);
|
||||||
|
|
||||||
|
int sat_config_write_example(FILE *stream);
|
||||||
|
int sat_config_write_example_file(char *path);
|
||||||
|
|
||||||
|
#endif // H_SATORI_CONFIG
|
21
include/context.h
Normal file
21
include/context.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef H_SATORI_CONTEXT
|
||||||
|
#define H_SATORI_CONTEXT
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "persist.h"
|
||||||
|
#include "futami.h"
|
||||||
|
|
||||||
|
typedef struct _satori_ctx {
|
||||||
|
time_t startup;
|
||||||
|
sat_config_ptr config;
|
||||||
|
sat_persist_ptr persist;
|
||||||
|
sat_futami_ptr futami;
|
||||||
|
} satori_ctx, *satori_ctx_ptr;
|
||||||
|
|
||||||
|
satori_ctx_ptr satori_ctx_alloc(void);
|
||||||
|
void satori_ctx_free(satori_ctx_ptr ctx);
|
||||||
|
|
||||||
|
#endif // H_SATORI_CONTEXT
|
36
include/curl_helper.h
Normal file
36
include/curl_helper.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef H_SATORI_CURL_HELPER
|
||||||
|
#define H_SATORI_CURL_HELPER
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
typedef struct _sat_curl_string {
|
||||||
|
char *str;
|
||||||
|
size_t length;
|
||||||
|
} sat_curl_string, *sat_curl_string_ptr;
|
||||||
|
|
||||||
|
sat_curl_string_ptr sat_curl_string_alloc(void);
|
||||||
|
void sat_curl_string_free(sat_curl_string_ptr str, bool freeArg);
|
||||||
|
void sat_curl_string_init(sat_curl_string_ptr str);
|
||||||
|
size_t sat_curl_string_write(char *ptr, size_t width, size_t count, sat_curl_string_ptr str);
|
||||||
|
|
||||||
|
typedef struct _sat_curl_url {
|
||||||
|
char *scheme;
|
||||||
|
char *host;
|
||||||
|
char *port;
|
||||||
|
char *path;
|
||||||
|
int flags; // don't touch this
|
||||||
|
} sat_curl_url, *sat_curl_url_ptr;
|
||||||
|
|
||||||
|
sat_curl_url_ptr sat_curl_url_alloc(void);
|
||||||
|
void sat_curl_url_free(sat_curl_url_ptr url, bool freeArg);
|
||||||
|
int sat_curl_url_parse(sat_curl_url_ptr url, char *str, char *scheme, char *host, char *port, char *path, bool supplyDefaults);
|
||||||
|
void sat_curl_url_owns_scheme(sat_curl_url_ptr url);
|
||||||
|
void sat_curl_url_owns_host(sat_curl_url_ptr url);
|
||||||
|
void sat_curl_url_owns_port(sat_curl_url_ptr url);
|
||||||
|
void sat_curl_url_owns_path(sat_curl_url_ptr url);
|
||||||
|
|
||||||
|
#endif // H_SATORI_CURL_HELPER
|
25
include/futami.h
Normal file
25
include/futami.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef H_SATORI_FUTAMI
|
||||||
|
#define H_SATORI_FUTAMI
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <json-c/json.h>
|
||||||
|
#include "curl_helper.h"
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
|
typedef struct _sat_futami {
|
||||||
|
int32_t ping;
|
||||||
|
size_t serversCount;
|
||||||
|
char **servers;
|
||||||
|
} sat_futami, *sat_futami_ptr;
|
||||||
|
|
||||||
|
sat_futami_ptr sat_futami_alloc(void);
|
||||||
|
void sat_futami_free(sat_futami_ptr ctx);
|
||||||
|
|
||||||
|
int sat_futami_load_json(sat_futami_ptr ctx, json_object *obj);
|
||||||
|
int sat_futami_load_json_file(sat_futami_ptr ctx, char *path);
|
||||||
|
int sat_futami_load_json_string(sat_futami_ptr ctx, char *str);
|
||||||
|
int sat_futami_load_json_url(sat_futami_ptr ctx, char *url);
|
||||||
|
|
||||||
|
#endif // H_SATORI_FUTAMI
|
20
include/macros.h
Normal file
20
include/macros.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef H_SATORI_VERSION
|
||||||
|
#define H_SATORI_VERSION
|
||||||
|
|
||||||
|
#define SATORI_NAME "Satori"
|
||||||
|
|
||||||
|
#ifndef SATORI_VERSION
|
||||||
|
# define SATORI_VERSION "20130127"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SATORI_USERAGENT (SATORI_NAME "/" SATORI_VERSION " (+https://fii.moe/satori)")
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
|
||||||
|
# define SATORI_OS_WIN
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# define SATORI_OS_MAC
|
||||||
|
#elif defined(__linux) || defined(__linux__) || defined(linux)
|
||||||
|
# define SATORI_OS_LIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
42
include/pack.h
Normal file
42
include/pack.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef H_SATORI_PACK
|
||||||
|
#define H_SATORI_PACK
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void sat_pack_i16be(uint8_t *buffer, int16_t num);
|
||||||
|
void sat_pack_u16be(uint8_t *buffer, uint16_t num);
|
||||||
|
|
||||||
|
void sat_pack_i32be(uint8_t *buffer, int32_t num);
|
||||||
|
void sat_pack_u32be(uint8_t *buffer, uint32_t num);
|
||||||
|
|
||||||
|
void sat_pack_i64be(uint8_t *buffer, int64_t num);
|
||||||
|
void sat_pack_u64be(uint8_t *buffer, uint64_t num);
|
||||||
|
|
||||||
|
void sat_pack_i16le(uint8_t *buffer, int16_t num);
|
||||||
|
void sat_pack_u16le(uint8_t *buffer, uint16_t num);
|
||||||
|
|
||||||
|
void sat_pack_i32le(uint8_t *buffer, int32_t num);
|
||||||
|
void sat_pack_u32le(uint8_t *buffer, uint32_t num);
|
||||||
|
|
||||||
|
void sat_pack_i64le(uint8_t *buffer, int64_t num);
|
||||||
|
void sat_pack_u64le(uint8_t *buffer, uint64_t num);
|
||||||
|
|
||||||
|
int16_t sat_unpack_i16be(uint8_t *buffer);
|
||||||
|
uint16_t sat_unpack_u16be(uint8_t *buffer);
|
||||||
|
|
||||||
|
int32_t sat_unpack_i32be(uint8_t *buffer);
|
||||||
|
uint32_t sat_unpack_u32be(uint8_t *buffer);
|
||||||
|
|
||||||
|
int64_t sat_unpack_i64be(uint8_t *buffer);
|
||||||
|
uint64_t sat_unpack_u64be(uint8_t *buffer);
|
||||||
|
|
||||||
|
int16_t sat_unpack_i16le(uint8_t *buffer);
|
||||||
|
uint16_t sat_unpack_u16le(uint8_t *buffer);
|
||||||
|
|
||||||
|
int32_t sat_unpack_i32le(uint8_t *buffer);
|
||||||
|
uint32_t sat_unpack_u32le(uint8_t *buffer);
|
||||||
|
|
||||||
|
int64_t sat_unpack_i64le(uint8_t *buffer);
|
||||||
|
uint64_t sat_unpack_u64le(uint8_t *buffer);
|
||||||
|
|
||||||
|
#endif // H_SATORI_PACK
|
34
include/persist.h
Normal file
34
include/persist.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef H_SATORI_PERIST
|
||||||
|
#define H_SATORI_PERIST
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <threads.h>
|
||||||
|
#include "pack.h"
|
||||||
|
|
||||||
|
typedef struct _sat_persist {
|
||||||
|
FILE *stream;
|
||||||
|
bool ownsStream;
|
||||||
|
long offset;
|
||||||
|
mtx_t *lock;
|
||||||
|
} sat_persist, *sat_persist_ptr;
|
||||||
|
|
||||||
|
sat_persist_ptr sat_persist_alloc(void);
|
||||||
|
void sat_persist_free(sat_persist_ptr ctx);
|
||||||
|
|
||||||
|
int sat_persist_create(sat_persist_ptr ctx, FILE *stream, bool ownsStream);
|
||||||
|
int sat_persist_create_file(sat_persist_ptr ctx, char *path);
|
||||||
|
void sat_persist_flush(sat_persist_ptr ctx);
|
||||||
|
int sat_persist_header_refresh(sat_persist_ptr ctx);
|
||||||
|
|
||||||
|
uint64_t sat_persist_get_fii_forum_last_post_id(sat_persist_ptr ctx);
|
||||||
|
void sat_persist_set_fii_forum_last_post_id(sat_persist_ptr ctx, uint64_t postId);
|
||||||
|
|
||||||
|
uint64_t sat_persist_get_fii_user_last_register_id(sat_persist_ptr ctx);
|
||||||
|
void sat_persist_set_fii_user_last_register_id(sat_persist_ptr ctx, uint64_t userId);
|
||||||
|
|
||||||
|
#endif // H_SATORI_PERIST
|
15
include/satori.h
Normal file
15
include/satori.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef H_SATORI
|
||||||
|
#define H_SATORI
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "pack.h"
|
||||||
|
#include "context.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "persist.h"
|
||||||
|
#include "futami.h"
|
||||||
|
#include "sock.h"
|
||||||
|
#include "websock.h"
|
||||||
|
#include "curl_helper.h"
|
||||||
|
|
||||||
|
#endif // H_SATORI
|
33
include/sock.h
Normal file
33
include/sock.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef H_SATORI_SOCK
|
||||||
|
#define H_SATORI_SOCK
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
typedef struct _sat_sock {
|
||||||
|
int sock;
|
||||||
|
} sat_sock, *sat_sock_ptr;
|
||||||
|
|
||||||
|
sat_sock_ptr sat_sock_alloc(void);
|
||||||
|
void sat_sock_free(sat_sock_ptr ctx);
|
||||||
|
int sat_sock_connect(sat_sock_ptr ctx, int addrFamily, int sockType, char *host, char *port);
|
||||||
|
int sat_sock_connect_tcp(sat_sock_ptr ctx, char *host, char *port);
|
||||||
|
void sat_sock_close(sat_sock_ptr ctx);
|
||||||
|
bool sat_sock_get_blocking(sat_sock_ptr ctx);
|
||||||
|
void sat_sock_set_blocking(sat_sock_ptr ctx, bool blocking);
|
||||||
|
int sat_sock_recv(sat_sock_ptr ctx, uint8_t *buffer, size_t size);
|
||||||
|
int sat_sock_send(sat_sock_ptr ctx, uint8_t *buffer, size_t count);
|
||||||
|
int sat_sock_select(sat_sock_ptr ctx, int timeout);
|
||||||
|
|
||||||
|
#endif // H_SATORI_SOCK
|
80
include/websock.h
Normal file
80
include/websock.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#ifndef H_SATORI_WEBSOCK
|
||||||
|
#define H_SATORI_WEBSOCK
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
|
typedef struct _sat_websock_close_info {
|
||||||
|
uint16_t code;
|
||||||
|
char *reason;
|
||||||
|
} sat_websock_close_info, *sat_websock_close_info_ptr;
|
||||||
|
|
||||||
|
typedef struct _sat_websock_ctx {
|
||||||
|
sat_sock_ptr sock;
|
||||||
|
sat_websock_close_info_ptr closeInfo;
|
||||||
|
sat_buffer_ptr buffer;
|
||||||
|
} sat_websock, *sat_websock_ptr;
|
||||||
|
|
||||||
|
sat_websock_ptr sat_websock_alloc(void);
|
||||||
|
void sat_websock_free(sat_websock_ptr ws);
|
||||||
|
void sat_websock_init(sat_websock_ptr ws, sat_sock_ptr sock);
|
||||||
|
void sat_websock_tidy(sat_websock_ptr ws);
|
||||||
|
void sat_websock_close(sat_websock_ptr ws, int closeCode, char *closeReason);
|
||||||
|
bool sat_websock_is_closed(sat_websock_ptr ws);
|
||||||
|
int sat_websock_buffer(sat_websock_ptr ws, size_t want);
|
||||||
|
int sat_websock_recv(sat_websock_ptr ws, uint8_t *buffer, size_t size);
|
||||||
|
int sat_websock_send(sat_websock_ptr ws, uint8_t *buffer, size_t count);
|
||||||
|
|
||||||
|
typedef enum _sat_websock_opcode {
|
||||||
|
// non-control
|
||||||
|
SAT_WEBSOCK_CONTINUE = 0,
|
||||||
|
SAT_WEBSOCK_TEXT,
|
||||||
|
SAT_WEBSOCK_BINARY,
|
||||||
|
// control
|
||||||
|
SAT_WEBSOCK_CLOSE = 8,
|
||||||
|
SAT_WEBSOCK_PING,
|
||||||
|
SAT_WEBSOCK_PONG,
|
||||||
|
} sat_websock_opcode;
|
||||||
|
|
||||||
|
typedef struct _sat_websock_frame_header {
|
||||||
|
bool isFinal;
|
||||||
|
sat_websock_opcode opcode;
|
||||||
|
bool isMasked;
|
||||||
|
char mask[4];
|
||||||
|
uint64_t length; // this max size is so ridiculous, should 127 just tell the server to fuck off?
|
||||||
|
uint64_t offset; // keeps track of data sent for masking
|
||||||
|
} sat_websock_frame_header, *sat_websock_frame_header_ptr;
|
||||||
|
|
||||||
|
void sat_websock_frame_recv_header(sat_websock_ptr ws, sat_websock_frame_header_ptr header);
|
||||||
|
int sat_websock_frame_recv(sat_websock_ptr ws, sat_websock_frame_header_ptr header, uint8_t *buffer, size_t size);
|
||||||
|
|
||||||
|
void sat_websock_frame_send_header(sat_websock_ptr ws, sat_websock_frame_header_ptr header);
|
||||||
|
int sat_websock_frame_send(sat_websock_ptr ws, sat_websock_frame_header_ptr header, uint8_t *buffer, size_t count);
|
||||||
|
|
||||||
|
typedef struct _sat_websock_handshake {
|
||||||
|
sat_websock_ptr websock;
|
||||||
|
|
||||||
|
char *host;
|
||||||
|
char *path;
|
||||||
|
char *origin;
|
||||||
|
char *protocol; // want to switch this to char** but i need to make a glue func first
|
||||||
|
char key[16];
|
||||||
|
|
||||||
|
bool completed;
|
||||||
|
bool upgraded;
|
||||||
|
uint16_t statusCode;
|
||||||
|
char *statusReason;
|
||||||
|
} sat_websock_handshake, *sat_websock_handshake_ptr;
|
||||||
|
|
||||||
|
sat_websock_handshake_ptr sat_websock_handshake_alloc(void);
|
||||||
|
void sat_websock_handshake_free(sat_websock_handshake_ptr hs, bool freeArg);
|
||||||
|
int sat_websock_handshake_gen_key(sat_websock_handshake_ptr hs);
|
||||||
|
int sat_websock_handshake_send(sat_websock_handshake_ptr hs);
|
||||||
|
int sat_websock_handshake_recv(sat_websock_handshake_ptr hs);
|
||||||
|
|
||||||
|
#endif // H_SATORI_WEBSOCK
|
179
src/buffer.c
Normal file
179
src/buffer.c
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
inline sat_buffer_piece_ptr sat_buffer_piece_alloc(void) {
|
||||||
|
sat_buffer_piece_ptr piece = malloc(sizeof(sat_buffer_piece));
|
||||||
|
piece->next = NULL;
|
||||||
|
return piece;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sat_buffer_piece_free(sat_buffer_piece_ptr piece) {
|
||||||
|
if(piece != NULL)
|
||||||
|
free(piece);
|
||||||
|
}
|
||||||
|
|
||||||
|
sat_buffer_ptr sat_buffer_alloc(void) {
|
||||||
|
sat_buffer_ptr buffer = malloc(sizeof(sat_buffer));
|
||||||
|
buffer->available = buffer->rPos = buffer->wPos = 0;
|
||||||
|
buffer->wCurrent = buffer->rCurrent = buffer->start = sat_buffer_piece_alloc();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_buffer_free(sat_buffer_ptr buffer) {
|
||||||
|
if(buffer == NULL) return;
|
||||||
|
|
||||||
|
sat_buffer_piece_ptr curr = buffer->start;
|
||||||
|
while(curr != NULL) {
|
||||||
|
buffer->start = curr->next;
|
||||||
|
free(curr);
|
||||||
|
curr = buffer->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sat_buffer_pending(sat_buffer_ptr buffer) {
|
||||||
|
return buffer->available > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sat_buffer_available(sat_buffer_ptr buffer) {
|
||||||
|
return buffer->available;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_buffer_tidy(sat_buffer_ptr buffer) {
|
||||||
|
// wCurrent should always be the same or ahead of rCurrent
|
||||||
|
|
||||||
|
sat_buffer_piece_ptr curr = buffer->start;
|
||||||
|
while(curr != NULL && curr != buffer->rCurrent) {
|
||||||
|
buffer->start = curr->next;
|
||||||
|
free(curr);
|
||||||
|
curr = buffer->start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_buffer_write(sat_buffer_ptr buffer, char *source, size_t count) {
|
||||||
|
if(buffer == NULL) return -1;
|
||||||
|
if(source == NULL) return -2;
|
||||||
|
|
||||||
|
if(count == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(buffer->wCurrent == NULL) {
|
||||||
|
buffer->wCurrent = buffer->start;
|
||||||
|
buffer->wPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = buffer->wPos;
|
||||||
|
sat_buffer_piece_ptr piece = buffer->wCurrent;
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
int shove;
|
||||||
|
while(count > 0) {
|
||||||
|
if(count + offset < SAT_BUFFER_PIECE_SIZE)
|
||||||
|
shove = count;
|
||||||
|
else if(offset < SAT_BUFFER_PIECE_SIZE)
|
||||||
|
shove = SAT_BUFFER_PIECE_SIZE - offset;
|
||||||
|
else {
|
||||||
|
offset = 0;
|
||||||
|
piece = (piece->next = sat_buffer_piece_alloc());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&piece->data[offset], source, shove);
|
||||||
|
|
||||||
|
offset += shove;
|
||||||
|
written += shove;
|
||||||
|
count -= shove;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->wPos = offset;
|
||||||
|
buffer->wCurrent = piece;
|
||||||
|
buffer->available += written;
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_buffer_putc(sat_buffer_ptr buffer, char value) {
|
||||||
|
if(buffer == NULL) return;
|
||||||
|
|
||||||
|
if(buffer->wCurrent == NULL) {
|
||||||
|
buffer->wCurrent = buffer->start;
|
||||||
|
buffer->wPos = 0;
|
||||||
|
} else if(buffer->wPos >= SAT_BUFFER_PIECE_MAX) {
|
||||||
|
buffer->wCurrent = (buffer->wCurrent->next = sat_buffer_piece_alloc());
|
||||||
|
buffer->wPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->wCurrent->data[buffer->wPos++] = value;
|
||||||
|
++buffer->available;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_buffer_read(sat_buffer_ptr buffer, char *target, size_t length) {
|
||||||
|
if(buffer == NULL) return -1;
|
||||||
|
if(target == NULL) return -2;
|
||||||
|
if(buffer->rCurrent == NULL) return -3;
|
||||||
|
|
||||||
|
if(length == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(buffer->rCurrent == NULL) {
|
||||||
|
buffer->rCurrent = buffer->start;
|
||||||
|
buffer->rPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remaining = length > buffer->available ? buffer->available : length;
|
||||||
|
if(remaining < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int offset = buffer->rPos;
|
||||||
|
sat_buffer_piece_ptr piece = buffer->rCurrent;
|
||||||
|
int read = 0;
|
||||||
|
|
||||||
|
int take;
|
||||||
|
while(remaining > 0) {
|
||||||
|
if(remaining + offset < SAT_BUFFER_PIECE_SIZE)
|
||||||
|
take = remaining;
|
||||||
|
else if(offset < SAT_BUFFER_PIECE_SIZE)
|
||||||
|
take = SAT_BUFFER_PIECE_SIZE - offset;
|
||||||
|
else {
|
||||||
|
offset = 0;
|
||||||
|
piece = piece->next;
|
||||||
|
|
||||||
|
// this shouldn't happen, maybe make this an assert?
|
||||||
|
if(piece == NULL)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(target, &piece->data[offset], take);
|
||||||
|
|
||||||
|
offset += take;
|
||||||
|
read += take;
|
||||||
|
remaining -= take;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->rPos = offset;
|
||||||
|
buffer->rCurrent = piece;
|
||||||
|
buffer->available -= read;
|
||||||
|
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
char sat_buffer_getc(sat_buffer_ptr buffer) {
|
||||||
|
if(buffer == NULL || buffer->rCurrent == NULL || buffer->available < 1)
|
||||||
|
return '\0';
|
||||||
|
|
||||||
|
if(buffer->rCurrent == NULL) {
|
||||||
|
buffer->rCurrent = buffer->start;
|
||||||
|
buffer->rPos = 0;
|
||||||
|
} else if(buffer->rPos >= SAT_BUFFER_PIECE_MAX) {
|
||||||
|
buffer->rCurrent = buffer->rCurrent->next;
|
||||||
|
buffer->rPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buffer->rCurrent == NULL)
|
||||||
|
return '\0';
|
||||||
|
|
||||||
|
--buffer->available;
|
||||||
|
|
||||||
|
return buffer->rCurrent->data[buffer->rPos++];
|
||||||
|
}
|
59
src/config/config.c
Normal file
59
src/config/config.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define SAT_CONFIG_LOCK_TIMEOUT (10)
|
||||||
|
#define SAT_CONFIG_CACHE_LIFETIME (900)
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_alloc(int type) {
|
||||||
|
if(type == SAT_CONFIG_TYPE_STREAM)
|
||||||
|
return sat_config_alloc_stream();
|
||||||
|
if(type == SAT_CONFIG_TYPE_SCOPED)
|
||||||
|
return sat_config_alloc_scoped();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_config_free(sat_config_ptr ctx) {
|
||||||
|
if(!ctx || !ctx->info) return;
|
||||||
|
|
||||||
|
if(ctx->type == SAT_CONFIG_TYPE_STREAM)
|
||||||
|
sat_config_free_stream(ctx);
|
||||||
|
else if(ctx->type == SAT_CONFIG_TYPE_SCOPED)
|
||||||
|
sat_config_free_scoped(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_scope_to(sat_config_ptr ctx, char *prefix) {
|
||||||
|
return ctx->scopeTo(ctx, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sat_config_read_value(sat_config_ptr ctx, char *name, char *fallback) {
|
||||||
|
return ctx->readValue(ctx, name, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sat_config_read_bool(sat_config_ptr ctx, char *name, bool fallback) {
|
||||||
|
char *raw = sat_config_read_value(ctx, name, NULL);
|
||||||
|
if(raw == NULL)
|
||||||
|
return fallback;
|
||||||
|
|
||||||
|
for(char *p = raw; *p; ++p)
|
||||||
|
*p = tolower(*p);
|
||||||
|
|
||||||
|
bool value = strcmp(raw, "0") != 0
|
||||||
|
&& strcmp(raw, "no") != 0
|
||||||
|
&& strcmp(raw, "false") != 0;
|
||||||
|
|
||||||
|
free(raw);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t sat_config_read_u64(sat_config_ptr ctx, char *name, uint64_t fallback) {
|
||||||
|
char *raw = sat_config_read_value(ctx, name, NULL);
|
||||||
|
if(raw == NULL)
|
||||||
|
return fallback;
|
||||||
|
|
||||||
|
char *end = NULL;
|
||||||
|
uint64_t value = strtoull(raw, &end, 10);
|
||||||
|
|
||||||
|
free(raw);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
65
src/config/config_example.c
Normal file
65
src/config/config_example.c
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
int sat_config_write_example(FILE *stream) {
|
||||||
|
if(stream == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char buff[70];
|
||||||
|
time_t curr = time(NULL);
|
||||||
|
struct tm dt = *localtime(&curr);
|
||||||
|
strftime(buff, sizeof buff, "%F %T", &dt);
|
||||||
|
|
||||||
|
fprintf(stream, "# Satori configuration\r\n");
|
||||||
|
fprintf(stream, "# Created on %s\r\n", buff);
|
||||||
|
fprintf(stream, "\r\n");
|
||||||
|
|
||||||
|
fprintf(stream, "# Sock Chat connection settings\r\n");
|
||||||
|
fprintf(stream, "sockchat:host ws://example.com/sockchat\r\n");
|
||||||
|
fprintf(stream, "sockchat:token AAAAAAAAAAAAAAAAAAAAAAAAA\r\n");
|
||||||
|
fprintf(stream, "\r\n");
|
||||||
|
|
||||||
|
fprintf(stream, "# Prefix character for commands, only the first character will be used\r\n");
|
||||||
|
fprintf(stream, "commands:prefix !\r\n");
|
||||||
|
fprintf(stream, "\r\n");
|
||||||
|
|
||||||
|
fprintf(stream, "# Booru settings\r\n");
|
||||||
|
fprintf(stream, "booru:prefix ~\r\n");
|
||||||
|
fprintf(stream, ";booru:danbooru:token username:token\r\n");
|
||||||
|
fprintf(stream, "\r\n");
|
||||||
|
|
||||||
|
fprintf(stream, "# Worknik API token\r\n");
|
||||||
|
fprintf(stream, ";wordnik:token tokengoeshere\r\n");
|
||||||
|
fprintf(stream, "\r\n");
|
||||||
|
|
||||||
|
fprintf(stream, "# Uiharu URL lookup settings\r\n");
|
||||||
|
fprintf(stream, "uiharu:enable true\r\n");
|
||||||
|
fprintf(stream, "\r\n");
|
||||||
|
|
||||||
|
fprintf(stream, "# Flashii broadcast settings\r\n");
|
||||||
|
fprintf(stream, "flashii:broadcasts:enable true\r\n");
|
||||||
|
fprintf(stream, "\r\n");
|
||||||
|
|
||||||
|
fprintf(stream, "# This option is here to ensure you actually did the configuration.\r\n");
|
||||||
|
fprintf(stream, "# You must remove it entirely, or set it to false if you're a fuckhead, or the program won't start.\r\n");
|
||||||
|
fprintf(stream, "exampleCfg:unedited true\r\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_config_write_example_file(char *path) {
|
||||||
|
if(path == NULL)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
FILE *stream = fopen(path, "wb");
|
||||||
|
|
||||||
|
int err = sat_config_write_example(stream);
|
||||||
|
if(err) {
|
||||||
|
if(stream) fclose(stream);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
fflush(stream);
|
||||||
|
fclose(stream);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
64
src/config/config_scoped.c
Normal file
64
src/config/config_scoped.c
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_scoped_scope_to(sat_config_ptr ctx, char *prefix) {
|
||||||
|
sat_config_scoped_ptr info = (sat_config_scoped_ptr)ctx->info;
|
||||||
|
|
||||||
|
int pfxLength = strlen(prefix);
|
||||||
|
bool appendColon = prefix[pfxLength - 1] != ':';
|
||||||
|
|
||||||
|
int length = strlen(info->prefix) + pfxLength + 1;
|
||||||
|
if(appendColon) length += 1;
|
||||||
|
|
||||||
|
char *newPrefix = malloc(length);
|
||||||
|
memset(newPrefix, 0, length);
|
||||||
|
strcat(newPrefix, info->prefix);
|
||||||
|
strcat(newPrefix, prefix);
|
||||||
|
if(appendColon) strcat(newPrefix, ":");
|
||||||
|
|
||||||
|
sat_config_ptr scoped = sat_config_alloc_scoped();
|
||||||
|
sat_config_scoped_ptr scopedInfo = (sat_config_scoped_ptr)scoped->info;
|
||||||
|
scopedInfo->parent = info->parent;
|
||||||
|
scopedInfo->prefix = newPrefix;
|
||||||
|
|
||||||
|
return scoped;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sat_config_scoped_read_value(sat_config_ptr ctx, char *name, char *fallback) {
|
||||||
|
sat_config_scoped_ptr info = (sat_config_scoped_ptr)ctx->info;
|
||||||
|
|
||||||
|
int length = strlen(info->prefix) + strlen(name) + 1;
|
||||||
|
char *realName = malloc(strlen(info->prefix) + strlen(name) + 1);
|
||||||
|
memset(realName, 0, length);
|
||||||
|
strcat(realName, info->prefix);
|
||||||
|
strcat(realName, name);
|
||||||
|
|
||||||
|
char *value = sat_config_read_value(info->parent, realName, fallback);
|
||||||
|
|
||||||
|
free(realName);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_alloc_scoped(void) {
|
||||||
|
sat_config_ptr ctx = malloc(sizeof(sat_config));
|
||||||
|
memset(ctx, 0, sizeof(sat_config));
|
||||||
|
ctx->type = SAT_CONFIG_TYPE_SCOPED;
|
||||||
|
ctx->scopeTo = sat_config_scoped_scope_to;
|
||||||
|
ctx->readValue = sat_config_scoped_read_value;
|
||||||
|
ctx->info = malloc(sizeof(sat_config_scoped));
|
||||||
|
memset(ctx->info, 0, sizeof(sat_config_scoped));
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_config_free_scoped(sat_config_ptr ctx) {
|
||||||
|
if(ctx == NULL || ctx->info == NULL || ctx->type != SAT_CONFIG_TYPE_SCOPED) return;
|
||||||
|
|
||||||
|
// freeing parent will cause explosions beyond your imagination
|
||||||
|
sat_config_scoped_ptr info = (sat_config_scoped_ptr)ctx->info;
|
||||||
|
|
||||||
|
if(info->prefix != NULL)
|
||||||
|
free(info->prefix);
|
||||||
|
|
||||||
|
free(ctx->info);
|
||||||
|
free(ctx);
|
||||||
|
}
|
159
src/config/config_stream.c
Normal file
159
src/config/config_stream.c
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_stream_scope_to(sat_config_ptr ctx, char *prefix) {
|
||||||
|
int pfxLength = strlen(prefix);
|
||||||
|
bool appendColon = prefix[pfxLength - 1] != ':';
|
||||||
|
|
||||||
|
int length = pfxLength + 1;
|
||||||
|
if(appendColon) length += 1;
|
||||||
|
|
||||||
|
char *newPrefix = malloc(length);
|
||||||
|
memset(newPrefix, 0, length);
|
||||||
|
strcat(newPrefix, prefix);
|
||||||
|
if(appendColon) strcat(newPrefix, ":");
|
||||||
|
|
||||||
|
sat_config_ptr scoped = sat_config_alloc_scoped();
|
||||||
|
sat_config_scoped_ptr scopedInfo = (sat_config_scoped_ptr)scoped->info;
|
||||||
|
scopedInfo->parent = ctx;
|
||||||
|
scopedInfo->prefix = newPrefix;
|
||||||
|
|
||||||
|
return scoped;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sat_config_stream_read_value(sat_config_ptr ctx, char *name, char *fallback) {
|
||||||
|
sat_config_stream_ptr info = (sat_config_stream_ptr)ctx->info;
|
||||||
|
|
||||||
|
// this buffer is reasonable, you are not
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
char *value = NULL;
|
||||||
|
|
||||||
|
// this buffer is also reasonable, you still aren't
|
||||||
|
// given this name is only used in strcmp and the index of the ending would be known
|
||||||
|
// there's honestly very little reason to not just replace the first trailing space
|
||||||
|
// with a \0 character and just passing buffer to strcmp
|
||||||
|
char cName[256] = {0};
|
||||||
|
int cNameLength;
|
||||||
|
|
||||||
|
// should retry for like 10 seconds
|
||||||
|
mtx_lock(info->lock);
|
||||||
|
|
||||||
|
fseek(info->stream, info->offset, SEEK_SET);
|
||||||
|
|
||||||
|
// probably do trimming later
|
||||||
|
while(fgets(buffer, sizeof buffer, info->stream) != NULL) {
|
||||||
|
if(buffer[0] == '\0' || buffer[0] == '\r' || buffer[0] == '\n'
|
||||||
|
|| buffer[0] == ' ' || buffer[0] == '#' || buffer[0] == ';')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// skip ridiculous lines too
|
||||||
|
if(buffer[(sizeof buffer) - 1] != '\0') {
|
||||||
|
memset(buffer, 0, sizeof buffer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cNameLength = 0;
|
||||||
|
while(buffer[cNameLength] != ' ' && buffer[cNameLength] != '\0')
|
||||||
|
++cNameLength;
|
||||||
|
|
||||||
|
cName[cNameLength] = '\0';
|
||||||
|
memcpy(cName, buffer, cNameLength);
|
||||||
|
|
||||||
|
if(strcmp(cName, name) == 0) {
|
||||||
|
int valueStart = cNameLength;
|
||||||
|
while(buffer[valueStart] == ' ')
|
||||||
|
++valueStart;
|
||||||
|
|
||||||
|
int valueEnd = valueStart;
|
||||||
|
while(buffer[valueEnd] != '\0' && buffer[valueEnd] != '\r' && buffer[valueEnd] != '\n')
|
||||||
|
++valueEnd;
|
||||||
|
|
||||||
|
int valueLength = valueEnd - valueStart;
|
||||||
|
if(valueLength > 0) {
|
||||||
|
value = malloc(valueLength + 1);
|
||||||
|
value[valueLength] = '\0';
|
||||||
|
memcpy(value, &buffer[valueStart], valueLength);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mtx_unlock(info->lock);
|
||||||
|
|
||||||
|
if(value == NULL && fallback != NULL) {
|
||||||
|
int length = strlen(fallback) + 1;
|
||||||
|
value = malloc(length);
|
||||||
|
memset(value, 0, length);
|
||||||
|
strcat(value, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
sat_config_ptr sat_config_alloc_stream(void) {
|
||||||
|
sat_config_ptr ctx = malloc(sizeof(sat_config));
|
||||||
|
memset(ctx, 0, sizeof(sat_config));
|
||||||
|
ctx->type = SAT_CONFIG_TYPE_STREAM;
|
||||||
|
ctx->scopeTo = sat_config_stream_scope_to;
|
||||||
|
ctx->readValue = sat_config_stream_read_value;
|
||||||
|
|
||||||
|
sat_config_stream_ptr info = malloc(sizeof(sat_config_stream));
|
||||||
|
memset(info, 0, sizeof(sat_config_stream));
|
||||||
|
ctx->info = (void*)info;
|
||||||
|
info->lock = malloc(sizeof(mtx_t));
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_config_free_stream(sat_config_ptr ctx) {
|
||||||
|
if(ctx == NULL || ctx->info == NULL || ctx->type != SAT_CONFIG_TYPE_STREAM) return;
|
||||||
|
|
||||||
|
sat_config_stream_ptr info = (sat_config_stream_ptr)ctx->info;
|
||||||
|
|
||||||
|
if(info->lock != NULL) {
|
||||||
|
mtx_destroy(info->lock);
|
||||||
|
free(info->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(info->ownsStream && info->stream != NULL)
|
||||||
|
free(info->stream);
|
||||||
|
|
||||||
|
free(ctx->info);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_config_stream_open(sat_config_ptr ctx, FILE *stream, bool ownsStream) {
|
||||||
|
if(ctx == NULL) return -10; // TODO: No.
|
||||||
|
if(ctx->type != SAT_CONFIG_TYPE_STREAM) return -11;
|
||||||
|
if(ctx->info == NULL) return -12;
|
||||||
|
|
||||||
|
sat_config_stream_ptr info = (sat_config_stream_ptr)ctx->info;
|
||||||
|
|
||||||
|
int err = mtx_init(info->lock, mtx_timed);
|
||||||
|
if(err == thrd_error) return -11;
|
||||||
|
|
||||||
|
info->stream = stream;
|
||||||
|
info->ownsStream = ownsStream;
|
||||||
|
|
||||||
|
// check for BOM
|
||||||
|
uint8_t buffer[3] = {0};
|
||||||
|
int read = fread(buffer, sizeof(uint8_t), sizeof buffer, stream);
|
||||||
|
if(buffer[0] != 0xEF || buffer[1] != 0xBB || buffer[2] != 0xBF)
|
||||||
|
fseek(stream, -read, SEEK_CUR);
|
||||||
|
|
||||||
|
info->offset = ftell(stream);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_config_stream_open_file(sat_config_ptr ctx, char *path) {
|
||||||
|
if(ctx == NULL) return -10; // TODO: No!
|
||||||
|
if(ctx->type != SAT_CONFIG_TYPE_STREAM) return -11;
|
||||||
|
if(ctx->info == NULL) return -12;
|
||||||
|
|
||||||
|
FILE *stream = fopen(path, "rb");
|
||||||
|
if(stream == NULL) return errno;
|
||||||
|
|
||||||
|
fseek(stream, 0, SEEK_SET);
|
||||||
|
|
||||||
|
return sat_config_stream_open(ctx, stream, true);
|
||||||
|
}
|
22
src/context.c
Normal file
22
src/context.c
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include "context.h"
|
||||||
|
|
||||||
|
satori_ctx_ptr satori_ctx_alloc(void) {
|
||||||
|
satori_ctx_ptr ctx = malloc(sizeof(satori_ctx));
|
||||||
|
memset(ctx, 0, sizeof(satori_ctx));
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void satori_ctx_free(satori_ctx_ptr ctx) {
|
||||||
|
if(ctx == NULL) return;
|
||||||
|
|
||||||
|
if(ctx->futami != NULL)
|
||||||
|
sat_futami_free(ctx->futami);
|
||||||
|
|
||||||
|
if(ctx->persist != NULL)
|
||||||
|
sat_persist_free(ctx->persist);
|
||||||
|
|
||||||
|
if(ctx->config != NULL)
|
||||||
|
sat_config_free(ctx->config);
|
||||||
|
|
||||||
|
free(ctx);
|
||||||
|
}
|
163
src/curl_helper.c
Normal file
163
src/curl_helper.c
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
#include "curl_helper.h"
|
||||||
|
|
||||||
|
sat_curl_string_ptr sat_curl_string_alloc(void) {
|
||||||
|
sat_curl_string_ptr str = malloc(sizeof(sat_curl_string));
|
||||||
|
sat_curl_string_init(str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_curl_string_free(sat_curl_string_ptr str, bool freeArg) {
|
||||||
|
if(str == NULL) return;
|
||||||
|
|
||||||
|
if(str->str)
|
||||||
|
free(str->str);
|
||||||
|
|
||||||
|
if(freeArg)
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_curl_string_init(sat_curl_string_ptr str) {
|
||||||
|
str->length = 0;
|
||||||
|
str->str = malloc(sizeof(char));
|
||||||
|
str->str[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sat_curl_string_write(char *ptr, size_t width, size_t count, sat_curl_string_ptr str) {
|
||||||
|
size_t newLength = width * count;
|
||||||
|
size_t totalLength = str->length + newLength;
|
||||||
|
|
||||||
|
str->str = realloc(str->str, totalLength + 1);
|
||||||
|
memcpy(str->str + str->length, ptr, newLength);
|
||||||
|
str->str[totalLength] = '\0';
|
||||||
|
|
||||||
|
str->length = totalLength;
|
||||||
|
|
||||||
|
return newLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SAT_CURL_URL_SCHEME_FREE (0x01)
|
||||||
|
#define SAT_CURL_URL_SCHEME_CURLFREE (0x02)
|
||||||
|
#define SAT_CURL_URL_HOST_FREE (0x04)
|
||||||
|
#define SAT_CURL_URL_HOST_CURLFREE (0x08)
|
||||||
|
#define SAT_CURL_URL_PORT_FREE (0x10)
|
||||||
|
#define SAT_CURL_URL_PORT_CURLFREE (0x20)
|
||||||
|
#define SAT_CURL_URL_PATH_FREE (0x40)
|
||||||
|
#define SAT_CURL_URL_PATH_CURLFREE (0x80)
|
||||||
|
|
||||||
|
sat_curl_url_ptr sat_curl_url_alloc(void) {
|
||||||
|
sat_curl_url_ptr url = malloc(sizeof(sat_curl_url));
|
||||||
|
memset(url, 0, sizeof(sat_curl_url));
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_curl_url_free(sat_curl_url_ptr url, bool freeArg) {
|
||||||
|
if(url == NULL) return;
|
||||||
|
|
||||||
|
if(url->scheme) {
|
||||||
|
if(url->flags & SAT_CURL_URL_SCHEME_CURLFREE)
|
||||||
|
curl_free(url->scheme);
|
||||||
|
else if(url->flags & SAT_CURL_URL_SCHEME_FREE)
|
||||||
|
free(url->scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(url->host) {
|
||||||
|
if(url->flags & SAT_CURL_URL_HOST_CURLFREE)
|
||||||
|
curl_free(url->host);
|
||||||
|
else if(url->flags & SAT_CURL_URL_HOST_FREE)
|
||||||
|
free(url->host);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(url->port) {
|
||||||
|
if(url->flags & SAT_CURL_URL_PORT_CURLFREE)
|
||||||
|
curl_free(url->port);
|
||||||
|
else if(url->flags & SAT_CURL_URL_PORT_FREE)
|
||||||
|
free(url->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(url->path) {
|
||||||
|
if(url->flags & SAT_CURL_URL_PATH_CURLFREE)
|
||||||
|
curl_free(url->path);
|
||||||
|
else if(url->flags & SAT_CURL_URL_PATH_FREE)
|
||||||
|
free(url->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(freeArg)
|
||||||
|
free(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// winapi eat your heart out
|
||||||
|
int sat_curl_url_parse(sat_curl_url_ptr url, char *str, char *scheme, char *host, char *port, char *path, bool supplyDefaults) {
|
||||||
|
if(str == NULL) return -1;
|
||||||
|
if(strlen(str) < 3) return -2;
|
||||||
|
|
||||||
|
CURLU *curl = curl_url();
|
||||||
|
if(!curl) return -3;
|
||||||
|
|
||||||
|
bool skipScheme = false;
|
||||||
|
CURLUcode err = curl_url_set(curl, CURLUPART_URL, str, CURLU_NON_SUPPORT_SCHEME);
|
||||||
|
if(err == CURLUE_BAD_SCHEME) {
|
||||||
|
// compensating for browsers interpreting //host as no scheme but curl not
|
||||||
|
if(str[0] == '/' && str[1] == '/') {
|
||||||
|
str += 2;
|
||||||
|
skipScheme = true;
|
||||||
|
} else return err;
|
||||||
|
|
||||||
|
err = curl_url_set(curl, CURLUPART_URL, str, CURLU_DEFAULT_SCHEME | CURLU_NON_SUPPORT_SCHEME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if(skipScheme || curl_url_get(curl, CURLUPART_SCHEME, &url->scheme, 0))
|
||||||
|
url->scheme = scheme;
|
||||||
|
else
|
||||||
|
url->flags |= SAT_CURL_URL_SCHEME_CURLFREE;
|
||||||
|
|
||||||
|
if(curl_url_get(curl, CURLUPART_HOST, &url->host, 0))
|
||||||
|
url->host = host;
|
||||||
|
else
|
||||||
|
url->flags |= SAT_CURL_URL_HOST_CURLFREE;
|
||||||
|
|
||||||
|
if(curl_url_get(curl, CURLUPART_PORT, &url->port, 0))
|
||||||
|
url->port = port;
|
||||||
|
else
|
||||||
|
url->flags |= SAT_CURL_URL_PORT_CURLFREE;
|
||||||
|
|
||||||
|
if(curl_url_get(curl, CURLUPART_PATH, &url->path, 0))
|
||||||
|
path = path;
|
||||||
|
else
|
||||||
|
url->flags |= SAT_CURL_URL_PATH_CURLFREE;
|
||||||
|
|
||||||
|
curl_url_cleanup(curl);
|
||||||
|
|
||||||
|
if(supplyDefaults) {
|
||||||
|
if(url->port == NULL && url->scheme != NULL) {
|
||||||
|
if(!strcmp(url->scheme, "https") || !strcmp(url->scheme, "wss"))
|
||||||
|
url->port = "443";
|
||||||
|
else if(!strcmp(url->scheme, "http") || !strcmp(url->scheme, "ws"))
|
||||||
|
url->port = "80";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_curl_url_owns_scheme(sat_curl_url_ptr url) {
|
||||||
|
if(!(url->flags & SAT_CURL_URL_SCHEME_CURLFREE))
|
||||||
|
url->flags |= SAT_CURL_URL_SCHEME_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_curl_url_owns_host(sat_curl_url_ptr url) {
|
||||||
|
if(!(url->flags & SAT_CURL_URL_HOST_CURLFREE))
|
||||||
|
url->flags |= SAT_CURL_URL_HOST_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_curl_url_owns_port(sat_curl_url_ptr url) {
|
||||||
|
if(!(url->flags & SAT_CURL_URL_PORT_CURLFREE))
|
||||||
|
url->flags |= SAT_CURL_URL_PORT_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_curl_url_owns_path(sat_curl_url_ptr url) {
|
||||||
|
if(!(url->flags & SAT_CURL_URL_PATH_CURLFREE))
|
||||||
|
url->flags |= SAT_CURL_URL_PATH_FREE;
|
||||||
|
}
|
124
src/futami.c
Normal file
124
src/futami.c
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#include "futami.h"
|
||||||
|
|
||||||
|
sat_futami_ptr sat_futami_alloc(void) {
|
||||||
|
return malloc(sizeof(sat_futami));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_futami_free(sat_futami_ptr ctx) {
|
||||||
|
if(ctx == NULL) return;
|
||||||
|
|
||||||
|
if(ctx->servers != NULL) {
|
||||||
|
while(ctx->serversCount > 0) {
|
||||||
|
--ctx->serversCount;
|
||||||
|
|
||||||
|
if(ctx->servers[ctx->serversCount] != NULL)
|
||||||
|
free(ctx->servers[ctx->serversCount]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ctx->servers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_futami_load_json(sat_futami_ptr ctx, json_object *obj) {
|
||||||
|
if(!obj) return -1;
|
||||||
|
|
||||||
|
json_object *value;
|
||||||
|
ctx->ping = json_object_object_get_ex(obj, "ping", &value)
|
||||||
|
? json_object_get_int(value)
|
||||||
|
: 69; // change default to 30, testing parsage
|
||||||
|
|
||||||
|
if(json_object_object_get_ex(obj, "servers", &value)) {
|
||||||
|
int serversCount = json_object_array_length(value);
|
||||||
|
ctx->serversCount = serversCount;
|
||||||
|
|
||||||
|
char **servers = calloc(serversCount, sizeof(char*));
|
||||||
|
ctx->servers = servers;
|
||||||
|
|
||||||
|
json_object *arrValue;
|
||||||
|
int arrStrLen;
|
||||||
|
const char* arrStr;
|
||||||
|
for(int i = 0; i < serversCount; ++i) {
|
||||||
|
arrValue = json_object_array_get_idx(value, i);
|
||||||
|
if(arrValue == NULL)
|
||||||
|
continue; // ???
|
||||||
|
|
||||||
|
arrStrLen = json_object_get_string_len(arrValue);
|
||||||
|
servers[i] = malloc(arrStrLen + 1);
|
||||||
|
servers[i][arrStrLen] = '\0';
|
||||||
|
|
||||||
|
if(arrStrLen > 0) {
|
||||||
|
arrStr = json_object_get_string(arrValue);
|
||||||
|
memcpy(servers[i], arrStr, arrStrLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx->serversCount = 0;
|
||||||
|
ctx->servers = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_futami_load_json_file(sat_futami_ptr ctx, char *path) {
|
||||||
|
json_object *obj = json_object_from_file(path);
|
||||||
|
if(!obj) return -11;
|
||||||
|
|
||||||
|
int err = sat_futami_load_json(ctx, obj);
|
||||||
|
|
||||||
|
json_object_put(obj);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_futami_load_json_string(sat_futami_ptr ctx, char *str) {
|
||||||
|
if(!str) return -21;
|
||||||
|
|
||||||
|
json_object *obj = json_tokener_parse(str);
|
||||||
|
|
||||||
|
int err = sat_futami_load_json(ctx, obj);
|
||||||
|
|
||||||
|
json_object_put(obj);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this only runs once during startup and is required to be completed before
|
||||||
|
// any connection is set up or module is loaded, but this should really be
|
||||||
|
// redone to be threaded or some shit rather than just block until done lol
|
||||||
|
int sat_futami_load_json_url(sat_futami_ptr ctx, char *url) {
|
||||||
|
if(!url) return -31;
|
||||||
|
|
||||||
|
CURL *curl;
|
||||||
|
CURLcode res;
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if(!curl)
|
||||||
|
return -32;
|
||||||
|
|
||||||
|
sat_curl_string str;
|
||||||
|
sat_curl_string_init(&str);
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 2L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, sat_curl_string_write);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &str);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, SATORI_USERAGENT);
|
||||||
|
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
if(res != CURLE_OK) // obv this random print shouldn't remain here
|
||||||
|
fprintf(stderr, "curl_easy_failed(): %s\r\n", curl_easy_strerror(res));
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
if(res != CURLE_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
int err = sat_futami_load_json_string(ctx, str.str);
|
||||||
|
|
||||||
|
sat_curl_string_free(&str, false);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
154
src/main.c
Normal file
154
src/main.c
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "satori.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
puts(" _____ __ _");
|
||||||
|
puts(" / ___/____ _/ /_____ _____(_)");
|
||||||
|
puts(" \\__ \\/ __ `/ __/ __ \\/ ___/ /");
|
||||||
|
puts(" ___/ / /_/ / /_/ /_/ / / / /");
|
||||||
|
puts("/____/\\__,_/\\__/\\____/_/ /_/");
|
||||||
|
puts("");
|
||||||
|
puts("Satori Testing Hole");
|
||||||
|
|
||||||
|
puts("Initialising Libraries...");
|
||||||
|
if(curl_global_init(CURL_GLOBAL_ALL)) {
|
||||||
|
puts("Failed to initialise cURL.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int err;
|
||||||
|
satori_ctx_ptr satori = satori_ctx_alloc();
|
||||||
|
satori->startup = time(NULL);
|
||||||
|
|
||||||
|
|
||||||
|
satori->config = sat_config_alloc_stream();
|
||||||
|
err = sat_config_stream_open_file(satori->config, "Satori.cfg");
|
||||||
|
|
||||||
|
if(err) {
|
||||||
|
printf("sat_config_stream_open_file: %d\r\n", err);
|
||||||
|
//return;
|
||||||
|
} else {
|
||||||
|
if(sat_config_read_bool(satori->config, "exampleCfg:unedited", false)) {
|
||||||
|
puts("Please review the configuration file before starting again.");
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *test = sat_config_read_value(satori->config, "test", NULL);
|
||||||
|
printf("sat_config_read_value: %s\r\n", test);
|
||||||
|
free(test);
|
||||||
|
|
||||||
|
|
||||||
|
sat_config_ptr scoped = sat_config_scope_to(satori->config, "sockchat");
|
||||||
|
|
||||||
|
test = sat_config_read_value(scoped, "host", NULL);
|
||||||
|
printf("sat_config_read_value: %s\r\n", test);
|
||||||
|
free(test);
|
||||||
|
|
||||||
|
sat_config_free(scoped);
|
||||||
|
|
||||||
|
|
||||||
|
sat_config_ptr scoped1 = sat_config_scope_to(satori->config, "flashii");
|
||||||
|
sat_config_ptr scoped2 = sat_config_scope_to(scoped1, "broadcasts");
|
||||||
|
|
||||||
|
sat_config_free(scoped1);
|
||||||
|
|
||||||
|
bool testb = sat_config_read_bool(scoped2, "enable", false);
|
||||||
|
printf("sat_config_read_bool: %s\r\n", testb ? "YES" : "NO");
|
||||||
|
|
||||||
|
sat_config_free(scoped2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
satori->persist = sat_persist_alloc();
|
||||||
|
err = sat_persist_create_file(satori->persist, "Persist.dat");
|
||||||
|
|
||||||
|
if(err) {
|
||||||
|
printf("sat_persist_create_file: %d\r\n", err);
|
||||||
|
//return;
|
||||||
|
} else {
|
||||||
|
if(sat_persist_get_fii_forum_last_post_id(satori->persist) < 1) {
|
||||||
|
puts("Importing Flashii last forum post id from legacy configuration...");
|
||||||
|
sat_persist_set_fii_forum_last_post_id(
|
||||||
|
satori->persist,
|
||||||
|
sat_config_read_u64(satori->config, "legacy:flashii:broadcasts:lastForumPostId", 0)
|
||||||
|
);
|
||||||
|
sat_persist_flush(satori->persist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sat_persist_get_fii_user_last_register_id(satori->persist) < 1) {
|
||||||
|
puts("Importing Flashii last joined user id from legacy configuration...");
|
||||||
|
sat_persist_set_fii_user_last_register_id(
|
||||||
|
satori->persist,
|
||||||
|
sat_config_read_u64(satori->config, "legacy:flashii:broadcasts:lastJoinUserId", 0)
|
||||||
|
);
|
||||||
|
sat_persist_flush(satori->persist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
satori->futami = sat_futami_alloc();
|
||||||
|
|
||||||
|
char *futamiUrl = sat_config_read_value(satori->config, "futami:common", NULL);
|
||||||
|
if(futamiUrl == NULL) {
|
||||||
|
puts("Missing Futami URL from config, cannot continue startup.");
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sat_futami_load_json_url(satori->futami, futamiUrl);
|
||||||
|
free(futamiUrl);
|
||||||
|
|
||||||
|
if(err) {
|
||||||
|
printf("sat_futami_load_json_url: %d\r\n", err);
|
||||||
|
//return;
|
||||||
|
} else {
|
||||||
|
printf("Ping Interval: %d seconds, Server count: %ld\r\n", satori->futami->ping, satori->futami->serversCount);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < satori->futami->serversCount; ++i)
|
||||||
|
printf(" - %s\r\n", satori->futami->servers[i]);
|
||||||
|
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(satori->futami->serversCount < 1) {
|
||||||
|
puts("There are no available servers.");
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sat_curl_url url = {0};
|
||||||
|
sat_curl_url_parse(&url, satori->futami->servers[0], "ws", NULL, NULL, "/", true);
|
||||||
|
|
||||||
|
sat_sock_ptr sock = sat_sock_alloc();
|
||||||
|
err = sat_sock_connect_tcp(sock, url.host, url.port);
|
||||||
|
sat_sock_set_blocking(sock, true);
|
||||||
|
|
||||||
|
sat_websock_ptr websock = sat_websock_alloc();
|
||||||
|
sat_websock_init(websock, sock);
|
||||||
|
|
||||||
|
sat_websock_handshake wshs = {0};
|
||||||
|
wshs.websock = websock;
|
||||||
|
wshs.host = url.host;
|
||||||
|
wshs.path = url.path;
|
||||||
|
sat_websock_handshake_gen_key(&wshs);
|
||||||
|
|
||||||
|
err = sat_websock_handshake_send(&wshs);
|
||||||
|
printf("sat_websock_handshake_send: %d\r\n", err);
|
||||||
|
|
||||||
|
|
||||||
|
err = sat_websock_handshake_recv(&wshs);
|
||||||
|
printf("sat_websock_handshake_recv: %d\r\n", err);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sat_sock_close(sock);
|
||||||
|
sat_sock_free(sock);
|
||||||
|
|
||||||
|
satori_ctx_free(satori);
|
||||||
|
|
||||||
|
puts("Cleaning up Libraries...");
|
||||||
|
curl_global_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
158
src/pack.c
Normal file
158
src/pack.c
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
#include "pack.h"
|
||||||
|
|
||||||
|
static inline void sat_pack_16be(uint8_t *buffer, uint16_t num) {
|
||||||
|
*buffer++ = num >> 8;
|
||||||
|
*buffer++ = num;
|
||||||
|
}
|
||||||
|
static inline void sat_pack_16le(uint8_t *buffer, uint16_t num) {
|
||||||
|
*buffer++ = num;
|
||||||
|
*buffer++ = num >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sat_pack_32be(uint8_t *buffer, uint32_t num) {
|
||||||
|
*buffer++ = num >> 24;
|
||||||
|
*buffer++ = num >> 16;
|
||||||
|
*buffer++ = num >> 8;
|
||||||
|
*buffer++ = num;
|
||||||
|
}
|
||||||
|
static inline void sat_pack_32le(uint8_t *buffer, uint32_t num) {
|
||||||
|
*buffer++ = num;
|
||||||
|
*buffer++ = num >> 8;
|
||||||
|
*buffer++ = num >> 16;
|
||||||
|
*buffer++ = num >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sat_pack_64be(uint8_t *buffer, uint64_t num) {
|
||||||
|
*buffer++ = num >> 56;
|
||||||
|
*buffer++ = num >> 48;
|
||||||
|
*buffer++ = num >> 40;
|
||||||
|
*buffer++ = num >> 32;
|
||||||
|
*buffer++ = num >> 24;
|
||||||
|
*buffer++ = num >> 16;
|
||||||
|
*buffer++ = num >> 8;
|
||||||
|
*buffer++ = num;
|
||||||
|
}
|
||||||
|
static inline void sat_pack_64le(uint8_t *buffer, uint64_t num) {
|
||||||
|
*buffer++ = num;
|
||||||
|
*buffer++ = num >> 8;
|
||||||
|
*buffer++ = num >> 16;
|
||||||
|
*buffer++ = num >> 24;
|
||||||
|
*buffer++ = num >> 32;
|
||||||
|
*buffer++ = num >> 40;
|
||||||
|
*buffer++ = num >> 48;
|
||||||
|
*buffer++ = num >> 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sat_pack_i16be(uint8_t *buffer, int16_t num) { sat_pack_16be(buffer, num); }
|
||||||
|
void sat_pack_u16be(uint8_t *buffer, uint16_t num) { sat_pack_16be(buffer, num); }
|
||||||
|
|
||||||
|
void sat_pack_i32be(uint8_t *buffer, int32_t num) { sat_pack_32be(buffer, num); }
|
||||||
|
void sat_pack_u32be(uint8_t *buffer, uint32_t num) { sat_pack_32be(buffer, num); }
|
||||||
|
|
||||||
|
void sat_pack_i64be(uint8_t *buffer, int64_t num) { sat_pack_64be(buffer, num); }
|
||||||
|
void sat_pack_u64be(uint8_t *buffer, uint64_t num) { sat_pack_64be(buffer, num); }
|
||||||
|
|
||||||
|
void sat_pack_i16le(uint8_t *buffer, int16_t num) { sat_pack_16le(buffer, num); }
|
||||||
|
void sat_pack_u16le(uint8_t *buffer, uint16_t num) { sat_pack_16le(buffer, num); }
|
||||||
|
|
||||||
|
void sat_pack_i32le(uint8_t *buffer, int32_t num) { sat_pack_32le(buffer, num); }
|
||||||
|
void sat_pack_u32le(uint8_t *buffer, uint32_t num) { sat_pack_32le(buffer, num); }
|
||||||
|
|
||||||
|
void sat_pack_i64le(uint8_t *buffer, int64_t num) { sat_pack_64le(buffer, num); }
|
||||||
|
void sat_pack_u64le(uint8_t *buffer, uint64_t num) { sat_pack_64le(buffer, num); }
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint16_t sat_unpack_16be(uint8_t *buffer) {
|
||||||
|
return ((uint16_t)buffer[0] << 8) | buffer[1];
|
||||||
|
}
|
||||||
|
static inline uint16_t sat_unpack_16le(uint8_t *buffer) {
|
||||||
|
return ((uint16_t)buffer[1] << 8) | buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t sat_unpack_32be(uint8_t *buffer) {
|
||||||
|
return ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16)
|
||||||
|
| ((uint32_t)buffer[2] << 8) | buffer[3];
|
||||||
|
}
|
||||||
|
static inline uint32_t sat_unpack_32le(uint8_t *buffer) {
|
||||||
|
return ((uint32_t)buffer[3] << 24) | ((uint32_t)buffer[2] << 16)
|
||||||
|
| ((uint32_t)buffer[1] << 8) | buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t sat_unpack_64be(uint8_t *buffer) {
|
||||||
|
return ((uint64_t)buffer[0] << 56) | ((uint64_t)buffer[1] << 48)
|
||||||
|
| ((uint64_t)buffer[2] << 40) | ((uint64_t)buffer[3] << 32)
|
||||||
|
| ((uint64_t)buffer[4] << 24) | ((uint64_t)buffer[5] << 16)
|
||||||
|
| ((uint64_t)buffer[6] << 8) | buffer[7];
|
||||||
|
}
|
||||||
|
static inline uint64_t sat_unpack_64le(uint8_t *buffer) {
|
||||||
|
return ((uint64_t)buffer[7] << 56) | ((uint64_t)buffer[6] << 48)
|
||||||
|
| ((uint64_t)buffer[5] << 40) | ((uint64_t)buffer[4] << 32)
|
||||||
|
| ((uint64_t)buffer[3] << 24) | ((uint64_t)buffer[2] << 16)
|
||||||
|
| ((uint64_t)buffer[1] << 8) | buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int16_t sat_sign_i16(uint16_t num) {
|
||||||
|
if(num <= 0x7FFFu)
|
||||||
|
return num;
|
||||||
|
|
||||||
|
return -1 - (int16_t)(0xFFFF - num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int32_t sat_sign_i32(uint32_t num) {
|
||||||
|
if(num <= 0x7FFFFFFFu)
|
||||||
|
return num;
|
||||||
|
|
||||||
|
return -1 - (int32_t)(0xFFFFFFFFu - num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int64_t sat_sign_i64(uint64_t num) {
|
||||||
|
if(num <= 0x7FFFFFFFFFFFFFFFu)
|
||||||
|
return num;
|
||||||
|
|
||||||
|
return -1 - (int64_t)(0xFFFFFFFFFFFFFFFFu - num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int16_t sat_unpack_i16be(uint8_t *buffer) {
|
||||||
|
return sat_sign_i16(sat_unpack_16be(buffer));
|
||||||
|
}
|
||||||
|
uint16_t sat_unpack_u16be(uint8_t *buffer) {
|
||||||
|
return sat_unpack_16be(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t sat_unpack_i32be(uint8_t *buffer) {
|
||||||
|
return sat_sign_i32(sat_unpack_32be(buffer));
|
||||||
|
}
|
||||||
|
uint32_t sat_unpack_u32be(uint8_t *buffer) {
|
||||||
|
return sat_unpack_32be(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t sat_unpack_i64be(uint8_t *buffer) {
|
||||||
|
return sat_sign_i64(sat_unpack_64be(buffer));
|
||||||
|
}
|
||||||
|
uint64_t sat_unpack_u64be(uint8_t *buffer) {
|
||||||
|
return sat_unpack_64be(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t sat_unpack_i16le(uint8_t *buffer) {
|
||||||
|
return sat_sign_i16(sat_unpack_16le(buffer));
|
||||||
|
}
|
||||||
|
uint16_t sat_unpack_u16le(uint8_t *buffer) {
|
||||||
|
return sat_unpack_16le(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t sat_unpack_i32le(uint8_t *buffer) {
|
||||||
|
return sat_sign_i32(sat_unpack_32le(buffer));
|
||||||
|
}
|
||||||
|
uint32_t sat_unpack_u32le(uint8_t *buffer) {
|
||||||
|
return sat_unpack_32le(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t sat_unpack_i64le(uint8_t *buffer) {
|
||||||
|
return sat_sign_i64(sat_unpack_64le(buffer));
|
||||||
|
}
|
||||||
|
uint64_t sat_unpack_u64le(uint8_t *buffer) {
|
||||||
|
return sat_unpack_64le(buffer);
|
||||||
|
}
|
147
src/persist.c
Normal file
147
src/persist.c
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
#include "persist.h"
|
||||||
|
|
||||||
|
#define SAT_PERSIST_MAGIC (0xDEAFB00B)
|
||||||
|
#define SAT_PERSIST_VERSION (0x01)
|
||||||
|
#define SAT_PERSIST_HEADER (0x10)
|
||||||
|
#define SAT_PERSIST_FII_FORUM_LAST_POST_ID (0x10)
|
||||||
|
#define SAT_PERSIST_FII_USER_LAST_REGISTER_ID (0x18)
|
||||||
|
|
||||||
|
// that version number is going to come in useful cuz i want to expand the Persist.dat format
|
||||||
|
// v2 should add the ability to define a field by name
|
||||||
|
// i'm avoiding using the word "table" because in my eyes that implies a single block of data
|
||||||
|
// rather the table should be a linked list with the first entry pointed at from the header
|
||||||
|
// this way the existing fields in the v1 format don't have to be moved elsewhere during conversion
|
||||||
|
// essentially we got [DEAFB00B 02000000 20000000 00000000] in the header,
|
||||||
|
// the pointer to the first entry is at offset 0x08 in the header and should be interpreted as a U32
|
||||||
|
// why not a U64? cuz if we're gonna need more than the size a 32-bit integer offers we have worse problems than offset overflows...
|
||||||
|
// each entry will have a variable size, starting with a null terminated ascii string, followed by a byte for the type,
|
||||||
|
// followed by a U32 pointing to the location of the data, followed by a final U32 pointing to the next entry
|
||||||
|
// !!! this would remove the "backwards compatibility" of not having to move the data, but wouldn't it make more sense to
|
||||||
|
// !!! [NAME TYPE PNEXT VALUE] rather than [NAME TYPE PNEXT PVALUE]?
|
||||||
|
// i do not know how i'd go about values of variable length, perhaps the function that allocates a space in the file can review
|
||||||
|
// empty space or some kind of index can be kept, perhaps just add an asterisk saying "do not variable length you will regret"
|
||||||
|
// perhaps leave variable length shit for a v3 format
|
||||||
|
|
||||||
|
sat_persist_ptr sat_persist_alloc(void) {
|
||||||
|
sat_persist_ptr ctx = malloc(sizeof(sat_persist));
|
||||||
|
memset(ctx, 0, sizeof(sat_persist));
|
||||||
|
ctx->lock = malloc(sizeof(mtx_t));
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_persist_free(sat_persist_ptr ctx) {
|
||||||
|
if(!ctx) return;
|
||||||
|
|
||||||
|
if(ctx->lock != NULL) {
|
||||||
|
mtx_destroy(ctx->lock);
|
||||||
|
free(ctx->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx->ownsStream && ctx->stream)
|
||||||
|
free(ctx->stream);
|
||||||
|
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_persist_create(sat_persist_ptr ctx, FILE *stream, bool ownsStream) {
|
||||||
|
if(ctx == NULL) return -10; // TODO: No.
|
||||||
|
|
||||||
|
int err;
|
||||||
|
err = mtx_init(ctx->lock, mtx_timed);
|
||||||
|
if(err == thrd_error) return -11;
|
||||||
|
|
||||||
|
ctx->stream = stream;
|
||||||
|
ctx->ownsStream = ownsStream;
|
||||||
|
ctx->offset = ftell(stream);
|
||||||
|
|
||||||
|
err = sat_persist_header_refresh(ctx);
|
||||||
|
if(err) return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_persist_create_file(sat_persist_ptr ctx, char *path) {
|
||||||
|
if(ctx == NULL) return -10; // TODO: No!
|
||||||
|
|
||||||
|
FILE *stream = fopen(path, "rb+");
|
||||||
|
if(stream == NULL) stream = fopen(path, "wb+");
|
||||||
|
if(stream == NULL) return errno;
|
||||||
|
|
||||||
|
fseek(stream, 0, SEEK_SET);
|
||||||
|
|
||||||
|
return sat_persist_create(ctx, stream, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_persist_flush(sat_persist_ptr ctx) {
|
||||||
|
if(ctx != NULL && ctx->stream != NULL)
|
||||||
|
fflush(ctx->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_persist_header_refresh(sat_persist_ptr ctx) {
|
||||||
|
uint8_t buffer[SAT_PERSIST_HEADER] = {0};
|
||||||
|
|
||||||
|
uint32_t magic;
|
||||||
|
|
||||||
|
mtx_lock(ctx->lock);
|
||||||
|
size_t read = fread(buffer, sizeof(uint8_t), SAT_PERSIST_HEADER, ctx->stream);
|
||||||
|
mtx_unlock(ctx->lock);
|
||||||
|
|
||||||
|
if(read == 0) {
|
||||||
|
sat_pack_u32be(buffer, SAT_PERSIST_MAGIC);
|
||||||
|
|
||||||
|
buffer[4] = SAT_PERSIST_VERSION;
|
||||||
|
|
||||||
|
mtx_lock(ctx->lock);
|
||||||
|
fseek(ctx->stream, ctx->offset, SEEK_SET);
|
||||||
|
fwrite(buffer, sizeof(uint8_t), SAT_PERSIST_HEADER, ctx->stream);
|
||||||
|
fflush(ctx->stream);
|
||||||
|
mtx_unlock(ctx->lock);
|
||||||
|
} else if(read < SAT_PERSIST_HEADER) {
|
||||||
|
return -2; // TODO: also no
|
||||||
|
} else {
|
||||||
|
magic = sat_unpack_u32be(buffer);
|
||||||
|
|
||||||
|
if(magic != SAT_PERSIST_MAGIC)
|
||||||
|
return -3; // TODO: still no
|
||||||
|
|
||||||
|
if(buffer[4] < 1 || buffer[4] > SAT_PERSIST_VERSION)
|
||||||
|
return -4; // TODO: again, no
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t sat_persist_read_u64(sat_persist_ptr ctx, uint32_t offset) {
|
||||||
|
uint8_t buffer[sizeof(uint64_t)] = {0};
|
||||||
|
|
||||||
|
mtx_lock(ctx->lock);
|
||||||
|
fseek(ctx->stream, ctx->offset + offset, SEEK_SET);
|
||||||
|
int read = fread(buffer, sizeof(uint8_t), sizeof(uint64_t), ctx->stream); // today we assume things will just work
|
||||||
|
mtx_unlock(ctx->lock);
|
||||||
|
if(read < 1) return 0;
|
||||||
|
|
||||||
|
return sat_unpack_u64le(buffer);
|
||||||
|
}
|
||||||
|
inline void sat_persist_write_u64(sat_persist_ptr ctx, uint32_t offset, uint64_t value) {
|
||||||
|
uint8_t buffer[sizeof(uint64_t)] = {0};
|
||||||
|
sat_pack_u64le(buffer, value);
|
||||||
|
|
||||||
|
mtx_lock(ctx->lock);
|
||||||
|
fseek(ctx->stream, ctx->offset + offset, SEEK_SET);
|
||||||
|
fwrite(buffer, sizeof(uint8_t), sizeof(uint64_t), ctx->stream);
|
||||||
|
mtx_unlock(ctx->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t sat_persist_get_fii_forum_last_post_id(sat_persist_ptr ctx) {
|
||||||
|
return sat_persist_read_u64(ctx, SAT_PERSIST_FII_FORUM_LAST_POST_ID);
|
||||||
|
}
|
||||||
|
void sat_persist_set_fii_forum_last_post_id(sat_persist_ptr ctx, uint64_t postId) {
|
||||||
|
sat_persist_write_u64(ctx, SAT_PERSIST_FII_FORUM_LAST_POST_ID, postId);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t sat_persist_get_fii_user_last_register_id(sat_persist_ptr ctx) {
|
||||||
|
return sat_persist_read_u64(ctx, SAT_PERSIST_FII_USER_LAST_REGISTER_ID);
|
||||||
|
}
|
||||||
|
void sat_persist_set_fii_user_last_register_id(sat_persist_ptr ctx, uint64_t userId) {
|
||||||
|
sat_persist_write_u64(ctx, SAT_PERSIST_FII_USER_LAST_REGISTER_ID, userId);
|
||||||
|
}
|
104
src/sock/sock_common.c
Normal file
104
src/sock/sock_common.c
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
|
sat_sock_ptr sat_sock_alloc(void) {
|
||||||
|
sat_sock_ptr ctx = malloc(sizeof(sat_sock));
|
||||||
|
memset(ctx, 0, sizeof(sat_sock));
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_sock_free(sat_sock_ptr ctx) {
|
||||||
|
if(ctx == NULL) return;
|
||||||
|
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_sock_connect(sat_sock_ptr ctx, int addrFamily, int sockType, char *host, char *port) {
|
||||||
|
struct addrinfo hints;
|
||||||
|
memset(&hints, 0, sizeof hints);
|
||||||
|
hints.ai_family = addrFamily;
|
||||||
|
hints.ai_socktype = sockType;
|
||||||
|
|
||||||
|
struct addrinfo *servInfo;
|
||||||
|
|
||||||
|
int err = getaddrinfo(host, port, &hints, &servInfo);
|
||||||
|
if(err) {
|
||||||
|
fprintf(stderr, "getaddrinfo(): %s\r\n", gai_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock = -1;
|
||||||
|
struct addrinfo *p;
|
||||||
|
for(p = servInfo; p != NULL; p = p->ai_next) {
|
||||||
|
if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
|
||||||
|
perror("socket():");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(connect(sock, p->ai_addr, p->ai_addrlen) == -1) {
|
||||||
|
close(sock);
|
||||||
|
perror("connect():");
|
||||||
|
sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(servInfo);
|
||||||
|
|
||||||
|
if(sock != -1)
|
||||||
|
ctx->sock = sock;
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_sock_connect_tcp(sat_sock_ptr ctx, char *host, char *port) {
|
||||||
|
return sat_sock_connect(ctx, AF_UNSPEC, SOCK_STREAM, host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_sock_close(sat_sock_ptr ctx) {
|
||||||
|
if(ctx->sock != -1) {
|
||||||
|
close(ctx->sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_sock_recv(sat_sock_ptr ctx, uint8_t *buffer, size_t size) {
|
||||||
|
return recv(ctx->sock, buffer, size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_sock_send(sat_sock_ptr ctx, uint8_t *buffer, size_t count) {
|
||||||
|
return send(ctx->sock, (char*)buffer, count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sat_sock_get_blocking(sat_sock_ptr ctx) {
|
||||||
|
return (fcntl(ctx->sock, F_GETFL) & O_NONBLOCK) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_sock_set_blocking(sat_sock_ptr ctx, bool blocking) {
|
||||||
|
int flags = fcntl(ctx->sock, F_GETFL);
|
||||||
|
if(blocking)
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
else
|
||||||
|
flags &= ~O_NONBLOCK;
|
||||||
|
|
||||||
|
fcntl(ctx->sock, F_SETFL, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_sock_select(sat_sock_ptr ctx, int timeout) {
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(ctx->sock, &rfds);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = timeout;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int state = select(ctx->sock + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
if(state == -1 || state == 0)
|
||||||
|
return state;
|
||||||
|
|
||||||
|
if(!FD_ISSET(ctx->sock, &rfds))
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
88
src/websock/websock.c
Normal file
88
src/websock/websock.c
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#include "websock.h"
|
||||||
|
|
||||||
|
sat_websock_ptr sat_websock_alloc(void) {
|
||||||
|
sat_websock_ptr websock = malloc(sizeof(sat_websock));
|
||||||
|
memset(websock, 0, sizeof(sat_websock));
|
||||||
|
return websock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_websock_free(sat_websock_ptr ws) {
|
||||||
|
if(ws == NULL) return;
|
||||||
|
|
||||||
|
if(ws->closeInfo != NULL)
|
||||||
|
free(ws->closeInfo);
|
||||||
|
|
||||||
|
if(ws->buffer != NULL)
|
||||||
|
free(ws->buffer);
|
||||||
|
|
||||||
|
free(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_websock_init(sat_websock_ptr ws, sat_sock_ptr sock) {
|
||||||
|
ws->sock = sock;
|
||||||
|
ws->buffer = sat_buffer_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_websock_tidy(sat_websock_ptr ws) {
|
||||||
|
sat_buffer_tidy(ws->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_websock_close(sat_websock_ptr ws, int closeCode, char *closeReason) {
|
||||||
|
// send close frame
|
||||||
|
|
||||||
|
// should the sock be nuked right away?
|
||||||
|
sat_sock_close(ws->sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sat_websock_is_closed(sat_websock_ptr ws) {
|
||||||
|
return ws != NULL && ws->closeInfo == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_websock_buffer(sat_websock_ptr ws, size_t want) {
|
||||||
|
size_t total = sat_buffer_available(ws->buffer);
|
||||||
|
if(total > want)
|
||||||
|
return total;
|
||||||
|
|
||||||
|
want -= total;
|
||||||
|
|
||||||
|
int read;
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
while(total < want) {
|
||||||
|
if(sat_sock_select(ws->sock, 2) > 0) {
|
||||||
|
read = sat_sock_recv(ws->sock, (uint8_t*)buffer, 1024);
|
||||||
|
if(read == -1)
|
||||||
|
return read;
|
||||||
|
|
||||||
|
total += read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_websock_recv(sat_websock_ptr ws, uint8_t *buffer, size_t size) {
|
||||||
|
size_t buffered = sat_buffer_available(ws->buffer);
|
||||||
|
if(buffered >= size)
|
||||||
|
return sat_buffer_read(ws->buffer, (char*)buffer, size);
|
||||||
|
|
||||||
|
size -= buffered;
|
||||||
|
|
||||||
|
size_t total = 0;
|
||||||
|
int read;
|
||||||
|
while(total < size) {
|
||||||
|
if(sat_sock_select(ws->sock, 2) > 0) {
|
||||||
|
read = sat_sock_recv(ws->sock, buffer, size);
|
||||||
|
if(read == -1)
|
||||||
|
return read;
|
||||||
|
|
||||||
|
buffer += read;
|
||||||
|
total += read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_websock_send(sat_websock_ptr ws, uint8_t *buffer, size_t count) {
|
||||||
|
return sat_sock_send(ws->sock, buffer, count);
|
||||||
|
}
|
71
src/websock/websock_handshake.c
Normal file
71
src/websock/websock_handshake.c
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include <sys/random.h>
|
||||||
|
#include "websock.h"
|
||||||
|
|
||||||
|
#define SAT_WEBSOCK_HANDSHAKE_UNIQUE "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||||
|
#define SAT_WEBSOCK_HANDSHAKE_VERSION_10 "HTTP/1.0 "
|
||||||
|
#define SAT_WEBSOCK_HANDSHAKE_VERSION_11 "HTTP/1.1 "
|
||||||
|
#define SAT_WEBSOCK_HANDSHAKE_LINE_END (0x0D0A)
|
||||||
|
|
||||||
|
sat_websock_handshake_ptr sat_websock_handshake_alloc(void) {
|
||||||
|
sat_websock_handshake_ptr hs = malloc(sizeof(sat_websock_handshake));
|
||||||
|
memset(hs, 0, sizeof(sat_websock_handshake));
|
||||||
|
return hs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sat_websock_handshake_free(sat_websock_handshake_ptr hs, bool freeArg) {
|
||||||
|
if(hs == NULL) return;
|
||||||
|
|
||||||
|
if(freeArg) free(hs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_websock_handshake_gen_key(sat_websock_handshake_ptr hs) {
|
||||||
|
return getrandom(hs->key, 16, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_websock_handshake_send(sat_websock_handshake_ptr hs) {
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
count += sprintf(buffer + count, "GET %s HTTP/1.1\r\n", hs->path);
|
||||||
|
count += sprintf(buffer + count, "Host: %s\r\n", hs->host);
|
||||||
|
count += sprintf(buffer + count, "Upgrade: websocket\r\n");
|
||||||
|
count += sprintf(buffer + count, "Connection: Upgrade\r\n");
|
||||||
|
count += sprintf(buffer + count, "Sec-WebSocket-Version: 13\r\n");
|
||||||
|
count += sprintf(buffer + count, "Sec-WebSocket-Key: %s\r\n", hs->key);
|
||||||
|
if(hs->origin != NULL) count += sprintf(buffer + count, "Origin: %s\r\n", hs->origin);
|
||||||
|
if(hs->protocol != NULL) count += sprintf(buffer + count, "Sec-WebSocket-Protocol: %s\r\n", hs->protocol);
|
||||||
|
count += sprintf(buffer + count, "\r\n");
|
||||||
|
|
||||||
|
return sat_websock_send(hs->websock, (uint8_t*)buffer, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sat_websock_handshake_recv(sat_websock_handshake_ptr hs) {
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
|
||||||
|
sat_websock_buffer(hs->websock, 100);
|
||||||
|
|
||||||
|
int expect = strlen(SAT_WEBSOCK_HANDSHAKE_VERSION_11);
|
||||||
|
int read = sat_websock_recv(hs->websock, (uint8_t*)buffer, expect);
|
||||||
|
if(read != expect) return -1;
|
||||||
|
if(strcmp(SAT_WEBSOCK_HANDSHAKE_VERSION_11, buffer) != 0
|
||||||
|
&& strcmp(SAT_WEBSOCK_HANDSHAKE_VERSION_10, buffer) != 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
uint16_t checkCrLf = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < sizeof buffer && checkCrLf != SAT_WEBSOCK_HANDSHAKE_LINE_END; ++i) {
|
||||||
|
buffer[i] = sat_buffer_getc(hs->websock->buffer);
|
||||||
|
checkCrLf <<= 8;
|
||||||
|
checkCrLf |= buffer[i];
|
||||||
|
}
|
||||||
|
buffer[i] = '\0';
|
||||||
|
|
||||||
|
if(sscanf(buffer, "%hd %s", &hs->statusCode, hs->statusReason) != 2)
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
hs->completed = true;
|
||||||
|
hs->upgraded = hs->statusCode == 101;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
7
win-amd64.sh
Normal file
7
win-amd64.sh
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
TARGET=satori-amd64.exe \
|
||||||
|
CC=x86_64-w64-mingw32-gcc \
|
||||||
|
CXX=x86_64-w64-mingw32-g++ \
|
||||||
|
LDFLAGS="-static-libgcc -static-libstdc++" \
|
||||||
|
make rebuild
|
7
win-ia32.sh
Normal file
7
win-ia32.sh
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
TARGET=satori-ia32.exe \
|
||||||
|
CC=i686-w64-mingw32-gcc \
|
||||||
|
CXX=i686-w64-mingw32-g++ \
|
||||||
|
LDFLAGS="-static-libgcc -static-libstdc++" \
|
||||||
|
make rebuild
|
Reference in a new issue