diff --git a/Makefile b/Makefile index 8d7759a..3765171 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,10 @@ EXTRA_LIBS= -lreadline -lrt -lconfig LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h INCLUDE=-I. -I${srcdir} CC=gcc -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o .SUFFIXES: diff --git a/Makefile.in b/Makefile.in index cf92f28..ba23e05 100644 --- a/Makefile.in +++ b/Makefile.in @@ -10,10 +10,10 @@ EXTRA_LIBS=@EXTRA_LIBS@ LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o .SUFFIXES: diff --git a/binlog.c b/binlog.c new file mode 100644 index 0000000..ec905d8 --- /dev/null +++ b/binlog.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "binlog.h" +#include "mtproto-common.h" +#include "net.h" + +#define LOG_START 0x8948329a +#define LOG_AUTH_KEY 0x984932aa +#define LOG_DEFAULT_DC 0x95382908 + +#define BINLOG_BUFFER_SIZE (1 << 20) +int binlog_buffer[BINLOG_BUFFER_SIZE]; +int *rptr; +int *wptr; +extern int test_dc; + +#define MAX_LOG_EVENT_SIZE (1 << 17) + +char *get_binlog_file_name (void); +extern struct dc *DC_list[]; +extern struct dc *DC_working; +extern int dc_working_num; + +void replay_log_event (void) { + assert (rptr < wptr); + int op = *rptr; + + in_ptr = rptr; + in_end = wptr; + switch (op) { + case LOG_START: + rptr ++; + return; + case CODE_dc_option: + fetch_dc_option (); + return; + case LOG_AUTH_KEY: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + assert (DC_list[num]); + DC_list[num]->auth_key_id = *(long long *)rptr; + rptr += 2; + memcpy (DC_list[num]->auth_key, rptr, 256); + rptr += 64; + }; + return; + case LOG_DEFAULT_DC: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + DC_working = DC_list[num]; + dc_working_num = num; + } + return; + } +} + +void create_new_binlog (void) { + static int s[1000]; + packet_ptr = s; + out_int (LOG_START); + out_int (CODE_dc_option); + out_int (0); + out_string (""); + out_string (test_dc ? TG_SERVER_TEST : TG_SERVER); + out_int (443); + + int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL); + assert (write (fd, s, (packet_ptr - s) * 4) == (packet_ptr - s) * 4); + close (fd); +} + + +void replay_log (void) { + if (access (get_binlog_file_name (), F_OK) < 0) { + printf ("No binlog found. Creating new one"); + create_new_binlog (); + } + int fd = open (get_binlog_file_name (), O_RDONLY); + if (fd < 0) { + perror ("binlog open"); + exit (2); + } + int end; + while (1) { + if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) { + if (wptr == rptr) { + wptr = rptr = binlog_buffer; + } else { + int x = wptr - rptr; + memcpy (binlog_buffer, rptr, 4 * x); + wptr -= x; + rptr -= x; + } + int l = (binlog_buffer + BINLOG_BUFFER_SIZE - wptr) * 4; + int k = read (fd, wptr, l); + if (k < 0) { + perror ("read binlog"); + exit (2); + } + assert (!(k & 3)); + if (k < l) { + end = 1; + } + wptr += (k / 4); + } + if (wptr == rptr) { break; } + replay_log_event (); + } + close (fd); +} diff --git a/binlog.h b/binlog.h new file mode 100644 index 0000000..a950682 --- /dev/null +++ b/binlog.h @@ -0,0 +1,6 @@ +#ifndef __BINLOG_H__ +#define __BINLOG_H__ + +void *alloc_log_event (int l); +void replay_log (void); +#endif diff --git a/binlog.tl b/binlog.tl new file mode 100644 index 0000000..c7c80b7 --- /dev/null +++ b/binlog.tl @@ -0,0 +1,10 @@ +log.peer peer_type:int peer_id:int = log.Peer; + +log.dc num:int hostname:string ip:string port:int = log.Event; +log.dcRenum old_num:int new_num:int = log.Event; +log.authKey dc:int key:bytes key_id:long = log.Event; +log.signIn dc:int id:int = log.Event; + + +log.user id:int flags:int access_hash:long first_name:string last_name:string real_first_name:string real_last_name:string phone:string photo:log.Photo photo_id:long photo_big:log.FileLocation photo_small:long.FileLocation = log.Event; + diff --git a/loop.c b/loop.c index 4bb3515..5cfcdb3 100644 --- a/loop.c +++ b/loop.c @@ -46,12 +46,14 @@ #include "queries.h" #include "telegram.h" #include "loop.h" +#include "binlog.h" extern char *default_username; extern char *auth_token; extern int test_dc; void set_default_username (const char *s); int default_dc_num; +extern int binlog_enabled; extern int unknown_user_list_pos; extern int unknown_user_list[]; @@ -426,6 +428,9 @@ int readline_active; int new_dc_num; int loop (void) { on_start (); + if (binlog_enabled) { + replay_log (); + } read_auth_file (); update_prompt (); diff --git a/queries.c b/queries.c index ed3fb47..7b58fb2 100644 --- a/queries.c +++ b/queries.c @@ -302,6 +302,23 @@ void out_random (int n) { /* {{{ Get config */ +void fetch_dc_option (void) { + assert (fetch_int () == CODE_dc_option); + int id = fetch_int (); + int l1 = prefetch_strlen (); + char *name = fetch_str (l1); + int l2 = prefetch_strlen (); + char *ip = fetch_str (l2); + int port = fetch_int (); + if (verbosity) { + logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + } + if (!DC_list[id]) { + alloc_dc (id, strndup (ip, l2), port); + new_dc_num ++; + } +} + int help_get_config_on_answer (struct query *q UU) { assert (fetch_int () == CODE_config); fetch_int (); @@ -318,20 +335,7 @@ int help_get_config_on_answer (struct query *q UU) { assert (n <= 10); int i; for (i = 0; i < n; i++) { - assert (fetch_int () == CODE_dc_option); - int id = fetch_int (); - int l1 = prefetch_strlen (); - char *name = fetch_str (l1); - int l2 = prefetch_strlen (); - char *ip = fetch_str (l2); - int port = fetch_int (); - if (verbosity) { - logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - } - if (!DC_list[id]) { - alloc_dc (id, strndup (ip, l2), port); - new_dc_num ++; - } + fetch_dc_option (); } max_chat_size = fetch_int (); if (verbosity >= 2) { diff --git a/queries.h b/queries.h index 49b10c0..32a613e 100644 --- a/queries.h +++ b/queries.h @@ -108,4 +108,8 @@ void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); void do_update_status (int online); void do_contacts_search (int limit, const char *s); + +// For binlog + +void fetch_dc_option (void); #endif